Hiding Types from Autoquery Metadata - metadata

I have an RDBMS AutoQuery setup with Custom QueryDb object which is the only object I wish to be exposed by Autoquery metadata, however, it is exposing all my ORMLite data objects to the UI. Is there an attribute that would hide these objects from the metadata as I want to control what can be queried?

If you're referring to the ServiceStack Admin UI AutoQueryMetadataFeature, you can remove Types and Operations in its MetadataFilter, e.g:
Plugins.Add(new AutoQueryMetadataFeature {
MaxLimit = ...,
MetadataFilter = res => {
res.Operations.RemoveAll(x => ...);
res.Types.RemoveAll(x => ...);
}
});

Related

how to set custom object with document id to a collection in firestore in flutter?

I defined a dart class A with some string variables and a list of objects of another class B.
I don't find any method function in cloud_firestore module to set this custom object of class A, as a document to the collection, even though custom objects are supported in Firestore. Do I need to convert all the members(strings, lists etc) of class A to JSON format or any other solution available?
In the event that it's inconvenient to create another collection of the related custom class, the only alternative is to build the related class instances yourself.
import Player from // player module
class GameState {
constructor(data) {
this.players = data.players.map(p => new Player(p))
// ...
}
// flatten GameState into a generic JS map
// build one of these on Player also
asFBData() {
const playerFBData = this.players.map(p => p.asFBData())
return { playerFBData, ...other_game_state_here }
}
}
const gameStateConverter = {
toFirestore: gameState => gameState.asFBData(),
fromFirestore: (snapshot, options) => new GameState(snapshot.data(options))
}
you cannot insert/update a plain Dart model. first, you need to your object into JSON data. for this, You can check this answer.
Also, you can check this answer.

Avoid lazyloader attribute

I´ve been looking for how avoid return a list without the attribute lazyLoader, I want to continue using the lazyLoader but I don´t want return the attribute when I return the whole list of my entity from my controller
I´m working with .NET core.
[
{
"lazyLoader": {},
"id": "id1"
"name": "name"
},
{
"lazyLoader": {},
"id": "id2",
"name": "name2"
}
]
You can do a select of you collection only retrieving the rest of the data.
That way your objects will not have the Navigation property at all.
db.YourCollection.Where(your condition)Select(x => new { id = x.id , name = x.name } );
In Entity Framework, if you have an object where one or more of its properties use lazy loading, check its runtime type name using GetType().Name. For an object of a Car class, for example, you will notice that the runtime type is actually something called CarProxy, which is a temporary in-memory type created by Entity Framework using reflection. This "fake" proxy class's base type is Car, and has all the original Car properties, but includes an extra one called LazyLoader for properties that may need it.
If you do further checking on this "fake" CarProxy type, you will also see that Assembly.IsDynamic = true, which is indicative that the class was created dynamically using reflection (see documentation):
var TheCar = DBContext.Cars.Find(1);
Console.WriteLine(TheCar.GetType().Assembly.IsDynamic.ToString()); //will echo "true"
Luckily, Newtonsoft.Json has an override on the JsonConvert.SerializeObject() method that allows us to provide a base type, so that the resulting JSON doesn't contain properties that don't exist in that type. So, to eliminate the LazyLoader property, just provide the object's BaseType as the type parameter:
var TheCar = DBContext.Cars.Find(1);
var TheJSON = Newtonsoft.Json.JsonConvert.SerializeObject(TheCar, TheCar.GetType().BaseType);
To make sure you don't get any circular reference loops when serializing (a very high probability when using lazy loading), call the serializer with the following setting:
var TheCar = DBContext.Cars.Find(1);
var Settings = new Newtonsoft.Json.JsonSerializerSettings
{
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
};
var TheJSON = Newtonsoft.Json.JsonConvert.SerializeObject(TheCar, TheCar.GetType().BaseType, Settings);
Note: This may only work on the first level deep when the serializer travels through the object. If there are yet more lazy-loading child properties of the object you provide to the serializer, the "LazyLoader" property may appear again. I haven't tested it so I can't say for sure.
I know this is old, but add
public boolean ShouldSerializeLazyLoader() { return false; }
to all the classes down the tree of the ones you want to serialize, and you will get a lazyloader free JSON.
Ref.: https://www.newtonsoft.com/json/help/html/ConditionalProperties.htm
The checked answer for this question is just working for the root object, if we have many nested lazyloaded objects, this solution will not work.
Although the answer of #Marcello-Barbiani is correct but it is not a good way to add this function to all entities we have.
The best way is create a new ContractResolver derived from DefaultContractResolver and check if property is Lazyloader then skip it as below:
public class NonLazyloaderContractResolver : DefaultContractResolver
{
public new static readonly NonLazyloaderContractResolver Instance = new NonLazyloaderContractResolver();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (property.PropertyName == "LazyLoader")
{
property.ShouldSerialize = i => false;
}
return property;
}
}
after that adding above class pass it through JsonSerializerSettings while serializing the object:
var json = JsonConvert.SerializeObject(newProduct, new JsonSerializerSettings() {
ContractResolver = new NonLazyloaderContractResolver(),
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore });
and finally if you are using asp.net core or asp.net core webapi add this contract as default contractresolver in startup.cs file:
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddJsonOptions(options =>
{
options.SerializerSettings.ContractResolver = new NonLazyloaderContractResolver();
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});

Can TableGateway Use Multiple Tables Zend Framework 2

In my module.php file, I want to pass multiple table names via TableGateway class in Zend Framework but I cannot find any documentation on it, other than it being limited to one table. The phpdoc for this (TableGateway) class says an array can be passed but again, I am not sure if it accepts more than one table.
for example in Module.php:
'Application\Model\LoginModel' => function($sm) {
$table_gateway = $sm->get('LoginService');
$table = new LoginModel($table_gateway);
return $table;
},
'LoginService' => function($sm) {
$db_adapter = $sm->get('Zend\Db\Adapter\Adapter');
$result_set_prototype = new ResultSet();
$result_set_prototype->setArrayObjectPrototype(new Login());
return new TableGateway(array('admins', 'members'), $db_adapter, null, $result_set_prototype);
}
Is it possible to do this and have multiple tables referenced or bound like this, or is it only designed to allow one table for each instance?
No it is not. Table Gateway object is intended to provide an object that represents a table in a database. Array can be passed to the constructor, but if you pass it, you will get InvalidArgumentException. Please check this code
https://github.com/zendframework/zend-db/blob/release-2.8.2/src/TableGateway/TableGateway.php#L34,L35
Please look at again TableGateway purposed on documentation here
https://framework.zend.com/manual/2.4/en/modules/zend.db.table-gateway.html

How to support OData query syntax but return non-Edm models

Exposing my EF models to an API always seemed wrong. I'd like my API to return a custom entity model to the caller but use EF on the back.
So I may have PersonRestEntity and a controller for CRUD ops against that and a Person EF code-first entity behind in and map values.
When I do this, I can no longer use the following to allow ~/people?$top=10 etc. in the URL
[EnableQuery]
public IQueryable<Person> Get(ODataQueryOptions<Person> query) { ... }
Because that exposes Person which is private DB implementation.
How can I have my cake and eat it?
I found a way. The trick is not to just return the IQueryable from the controller, because you need to materialise the query first. This doesn't mean materialising the whole set into RAM, the query is still run at the database, but by explicitly applying the query and materialising the results you can return mapped entities thereafter.
Define this action, specifying the DbSet entity type:
public async Task<HttpResponseMessage> Get(ODataQueryOptions<Person> oDataQuery)
And then apply the query manually to the DbSet<Person> like so:
var queryable = oDataQuery.ApplyTo(queryableDbSet);
Then use the following to run the query and turn the results into the collection of entities you publicly expose:
var list = await queryable.ToListAsync(cancellationToken);
return list
.OfType<Person>()
.Select(p => MyEntityMapper.MapToRestEntity(p));
Then you can return the list in an HttpResponseMessage as normal.
That's it, though obviously where the property names between the entities don't match or are absent on either class, there's going to be some issues, so its probably best to ensure the properties you want to include in query options are named the same in both entities.
Else, I guess you could choose to not support filters and just allow $top and $skip and impose a default order yourself. This can be achieved like so, making sure to order the queryable first, then skip, then top. Something like:
IQueryable queryable = people
.GetQueryable(operationContext)
.OrderBy(r => r.Name);
if (oDataQuery.Skip != null)
queryable = oDataQuery.Skip.ApplyTo(queryable, new System.Web.OData.Query.ODataQuerySettings());
if (oDataQuery.Top != null)
queryable = oDataQuery.Top.ApplyTo(queryable, new System.Web.OData.Query.ODataQuerySettings());
var list = await queryable.ToListAsync(operationContext.CreateToken());
return list
.OfType<Person>()
.Select(i => this.BuildPersonEntity(i));
More information:
If you simply use the non-generic ODataQueryOptions you get
Cannot create an EDM model as the action 'Get' on controller 'People'
has a return type 'System.Net.Http.HttpResponseMessage' that does not
implement IEnumerable
And other errors occur under different circumstances.

How can a waterline adapter get access to attributes defined in the model?

I am building a Sails/WaterLine adaptor for RestLike datasource. In order to return instances to WaterLine I need to transform the result to handle things like dates and null. To do this I need access to the attribute definitions on the model. But I can't figure out how to get access to them.
sails-rest appears to somehow store a definition object on the connection and then uses it later to format results. This is pretty much what I need, but I do not see how this definition object is derived in the first place.
How can a waterline adapter get access to attributes defined in the model?
found it!
The registerConnection method, gets the collections argument
That object contains all the models and their definitions. Store it on the connection so you can reference it later in the other adapter methods.
registerConnection: function(connection, collections, cb) {
if(!connection.identity) return cb(new Error('Connection is missing an identity.'));
if(connections[connection.identity]) return cb(new Error('Connection is already registered.'));
// Add in logic here to initialize connection
// e.g. connections[connection.identity] = new Database(connection, collections);
var dbConnection = '... create connection here ...'
connections[connection.identity] = {
dbConnection : dbConnection,
collections : collections // <-- store collection
}
cb();
}
...later in the other functions where you need the model definition
create: function (connection, collection, values, cb){
// database connection
var dbConnection = connections[connection].dbConnection;
// model definition
var definition = connections[connection].collections[collection].definition
// do the rest of the stuff
}