Using OData with Automapper and EF core to expose the data model below,
Customer
CustomerMetric: CustomerLevel,VIPFlag,other fields...
Customer has one to many relationship with CustomerMetric. Goal is to for the Customer controller to expose CustomerLevel,VIPFlag in the first matching row from the CustomerMetric table.
What I did in the map config,
.ForMember(dest => dest.CustomerLevel, opt => opt.MapFrom(src => src.CustomerMetric.FirstOrDefault().Level))
.ForMember(dest => dest.VIPFlag , opt => opt.MapFrom(src => src.CustomerMetric.FirstOrDefault().VIPFlag ))
This is all good, values are populated correctly. However, automapper are triggering two calls to the database, with 'select top 1 CustomerLevel' and another one with 'select top 1 VIPFlag'.
How to make it possible that with one call to fetch both fields rather than two calls for each individual field? I tried .Include on the controller it does not work..
Thanks!!
You can try grouping those two in a struct or class and then map the whole thing. That would work in EF6, I'm not sure about EF core. See this.
Related
I'm trying to update products(incl. variants) via DAL. The problem I'm facing right now is that if I'm writing the properties, new ones will be added and old ones(even if they aren't included in the data) will stay aswell. What's the best way on updating the product including the replacement of the properties?
$product = [
'id' => $id,
'properties' => $properties
];
$this->productRepository->update([$product], $this->context);
I fixed it by deleting the properties manually by getting the old properties from the current product in the db and creating the diff between the new properties and the old ones. I then deleted the old entries in the product_property table.
$this->productPropertyRepo->delete([[
'productId' => $product['id'],
'optionId' => $propertyId
]], $this->context);
If someone knows an easier way feel free to post another answer.
It is ok to use custom variables in the aggregation for the feed?
When I push my activity I push the following
$data = [
'actor' => '1',
'verb' => "$verb",
'object' => "$objectType:$objectId",
'target' => "$targetObjectType:$targetObjectId",
'time' => "$time",
'foreign_id' => "$foreignId",
// Custom field
'object_type' => $objectType
];
It mentions when editing the aggregation feed:
The following variables are
available to you: verb, time, object, target, id, actor.
The reason I want a custom variable is that I want to aggregate by VERB TARGET and OBJECT(TYPE). So that I can show things such as 10 points were added to your item of id 1. If we use the id as well such as object=point:1 then we can't use this in the aggregation since it will be different id for each point hence never
aggregate.
I just tried using a custom variable in the aggregation and it seems to be
available and works. Is anything wrong in doing that?
Yes, you can use custom variables in your aggregation format. There is nothing wrong with doing so. In fact it's a great solution which gives you a lot of control over the aggregation. We should clarify that more clearly in the interface.
I ' ve some troubles , managing my i18n in my database
For now I ' just two languages available on my application , but in order to be scalable, I would like to do it the "best" way.
I could have duplicated all fields like description_fr, description_en but I was no confortable with this at all. What I've done for now, is a external table , call it content, and its architecture is like this :
id_ref => entity referenced id (2)
type => table name (university)
field => field of the specific table (description)
lang => which lang (fr, en, es…)
content => and finally the appropriate content.
I think it can be important to precise, I use sequelizeJS as ORM. So I can use a usefull hooks as afterFind, afterCreate and afterUpdate. So Each time I wanna to find a resource for example, after find it, my hook retrieve all content for this resource and set definitly my object with goods values. It works, but I'm not in love with this.
But I have some troubles with this :
It's increase considerably my number of requests to the database : If I select 50 rows for example, I have to do 50 requests more.. , and just for a particular model. If I have nested models, it's exponential…
Then, It's complicated to fetch data by content i18ned. Example find a university with a specific name is complicated.
And It's a lot of work for updating etc...
So I wonder, if it would be a good idea , to save as a JSON, directly in the table concerned , the data. Something like
{
fr : { 'name':'Ma super université' },
en : { 'name':'My kick ass university' }
}
And keep on using Sequelize Hooks to build and insert proper data into my object.
What do you think ?
How do you manage this ?
EDIT
I use a mysql database
It concerns around 20 fields (cross models)
I have to set the default value using a my default_lang if there is no content set (e.g, event.description in french will be the same as the english one, if there is no content set)
I used this npm package sequelize-i18n. It worked pretty fine for me using sequelize 3.23.2, unfortunately it seems does not have support for sequelize 4.x yet.
No matter how hard I tried I couldn't make it work and I'm not sure if it is possible.
I want to select all clients who have at least one order.
The first thing I tried was db.Exists as following:
SqlExpression<Client> exp = OrmLiteConfig.DialectProvider.SqlExpression<Client>();
exp.Where(x => Db.Exists<Order>(z => z.ClientId == x.Id));
but I get the following error
variable 'x' of type '[assembly].Client' referenced from scope '', but it is not defined`
Second try was using Join and SelectDistinct:
SqlExpression<Client> exp = OrmLiteConfig.DialectProvider.SqlExpression<Client>();
ev.Join<Client, Order>((b, a) => b.Id == a.ClientId)
.SelectDistinct(x => new { x.Id, x.ClientNumber, x.ClientNameName});
Although not optimal it worked, up to the moment when I needed paging for the result set through
ev.Limit(skip:((request.Page-1) * request.PageSize), rows:request.PageSize)
When using Limit the distinct logically get ignored in building the query, so I get now duplicate Clients.
Is there any other way, or in general is there away to handle subqueries in OrmLite?
Any help is appreciated.
ServiceStack OrmLite (currently at 4.0.x) does not have support for subqueries.
If you look at the 4.0.x docs , there is no discussion of subqueries. JOIN support has been added recently, but for advanced SQL, you need to write it yourself.
Honestly, at a certain point of complexity, SQL is more readable than advanced ORM/LINQ-style queries.
I created middleware layer between the BL and the Entity Framework DAL for filtering the data by the user permission business logic in the application. My layer implements IObjectSet that have an instance of the "None filtered ObjectSet" and the filter expression is running whenever the ObjectSet is in use. All working grate, instead of the method "Include". I found a solution that create an extension method that convert the "None filtered ObjectSet" to ObjectQuery and use the ObjectQuery.Include method but this solution can cause a bypass of the permission filtering.
public IQueryable<TEntity> Include<TJoin>(string path)
{
if (_nonAuthorizedObjectSet is ObjectQuery<TEntity>)
{
var result = ((ObjectQuery<TEntity>)_nonAuthorizedObjectSet).Include(path);
return result as IQueryable<TEntity>;
}
}
For example:
Table name "Items" have columns {Item_Id,Owner,Item_Type_Id}
This table have a permission logic that the user can only see the items that the Owner==user.
Table "Item_Types" have no permission logic.
By doing:
PermittedDAL. Items.ToArray() – get only the items that the current_user==Owner.
Item_Types.Include("Items")
Problem!! - I get all the items.
Thanks
EF does not support filtering eager loaded records (Include). Only main records can be filtered. If you need to filter relations you must either use custom projections or separate queries for each relation.