webapi entity frameworks - best way to return nested classes where - entity-framework

Based on this diagram using webapi entity frameworks, what would be the best way to say, return me all Menus.text.... where AspNetUsers.Username = xxxx.
I think I need to start with a MenusController, and say return Menus(Include Permissions, include groups, include AspNetUsers, where username = x.
Is that the best way?

If you only need text field of menu, not use include, better is use projection to load desired fields as following:
var menuTextList = db.Users.Where(e=> e.Username = "xxxx")
.Select(e=> e.Group)
.SelectMany(e=> e.Permissions)
.Select(e=> e.Menu)
.Select(e=> e.text)
.Distinct()
.ToList();
and for all fields in menus, as following:
var munuList = db.Users.Where(e=> e.Username = "xxxx")
.Select(e=> e.Group)
.SelectMany(e=> e.Permissions)
.Select(e=> e.Menu)
.Distinct()
.ToList();

Related

use Intersect into IQueryable and EfCore

I'm trying to use LinQ Intersect (or equivalent) into an IQueryable method but it seems like I'm doing it wrong.
I have some PRODUCTS that match some SPECIFITY (like colors, materials, height...), those specifications have different values, for example:
color : blue, red, yellow
height : 128cm, 152cm...
I need to get the products that match ALL the list of couple specifityId / specifityValue I provide.
Here what I'm trying to do:
// The list of couple SpecifityID (color, material..) / SpecifityValue (red, yellow, wood...)
List<string> SpecId_SpecValue = new List<string>();
SpecId_SpecValue.Add("3535a444-1139-4a1e-989f-795eb9be43be_BEA");
SpecId_SpecValue.Add("35ad6162-a885-4a6a-8044-78b68f6b2c4b_Purple");
int filterCOunt = SpecId_SpecValue.Count;
var query =
Products
.Include(pd => pd.ProductsSpecifity)
.Where(z => SpecId_SpecValue
.Intersect(z.ProductsSpecifity.Select(x => (x.SpecifityID.ToString() + "_" + x.SpecifityValue)).ToList()).Count() == filterCOunt);
I got the error : InvalidOperationException: The LINQ expression 'DbSet() could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information. which mean it can't be translated to SQL and I need to ToList before my filter.
The problem is, I don't want to call ToList() because I got huge number of products in my Database and I don't want to load them in memory before filtering them.
Is there an other way to achieve what I need to do?
I ended up using a solution found in the link #Gert Arnold provide here.
I used BlazarTech.QueryableValues.SqlServer #yv989c's answers
Here's what is now working like a charm :
// The list of couple SpecifityID (color, material..) / SpecifityValue (red, yellow, wood...)
Dictionary<Guid, string> SpecId_SpecValue = new Dictionary<Guid, string>();
SpecId_SpecValue.Add(new Guid("3535a444-1139-4a1e-989f-795eb9be43be"), "BEA");
SpecId_SpecValue.Add(new Guid("35ad6162-a885-4a6a-8044-78b68f6b2c4b"), "Purple");
// BlazarTech.QueryableValues.SqlServer
var queryableValues = DbContext.AsQueryableValues(SpecId_SpecValue);
var query = Products.Include(pd => pd.ProductsSpecifity)
.Where(x => x.ProductsSpecifity
.Where(e => queryableValues
.Where(v =>
v.Key == e.SpecifityID &&
v.Value == e.SpecifityValue
)
.Any()
).Count() == dynamicFilter.Count);
The query expresses "products of which all x.SpecifityID.ToString() + "_" + x.SpecifityValue combinations exactly match some given combinations".
Set combination operators like Except often don't play nice with EF for various reasons I'm not going into here. Fortunately, in many of these cases a work-around can be found by using Contains, which EF does support well. In your case:
var query = Products.Include(pd => pd.ProductsSpecifity)
.Where(z => z.ProductsSpecifity
.Select(x => x.SpecifityID.ToString() + "_" + x.SpecifityValue)
.Count(s => SpecId_SpecValue.Contains(s)) == filterCount);
Please note that the comparison is not efficient. Transforming database values before comparison disables any use of indexes (is not sargable). But doing this more efficiently isn't trivial in EF, see this.

Dynamic query in EF using Expression

I am trying to understand what is the best way to create a dynamic query.
I have a requirement where I will be writing an API to retrieve data from DB. the API has lot of filter paramters. eg. I need to retrieve movies that can be filtered on following properties.
MovieName, Genere, Rating, Language, Category
I can give these parameters in any combination.. so in my Data layer I started framing my dynamic query like this.
IQueryable<Movie> qryContext = null;
if(!string.isnullorEmpty(request.MovieName))
qryContext = context.Movies.Where(x => x.MovieName == request.MovieName)
if(!string.isnullorEmpty(request.Genere))
qryContext = context.Movies.Where(x => x.Genere == request.Genere)
if(!string.isnullorEmpty(request.Language))
qryContext = context.Movies.Where(x => x.Language == request.Language)
if(!string.isnullorEmpty(request.Category))
qryContext = context.Movies.Where(x => x.Category == request.Category)
if(qryContext!= null)
return qryContext.ToList();
else
return null;
Based on the given parameters, the sql query is framed..
But When I search in google reg dynamic queries in EF, most of the links refer to using Expression. Do I need to make use of Expression or can I proeeed with the above method.
Also let me know what advantage I get on using expressions.
Basically what you see inside the Where(...) is expression.
In your example this would be x => x.Language == request.Language
if(!string.isnullorEmpty(request.Language)) qryContext = context.Movies.Where(x => x.Language == request.Language)
Also, I would recommend you to take a look into the Dynamic expression library from EF Plus team. Here https://dynamic-linq.net/basic-simple-query
This allows you to pass expression as a string. And you can construct your filters in the Frontend, and pass them as a string, which helps you to write a much cleaner implementation of filters.

How To specify Where in Include in entity framework

I have faced this issue many times and I wanted to know the best approach to deal with Where clause in Include. Here is my sample code
IEnumerable<Data.StoreMenu> dataStoreMenus = _context.StoreMenus
.Include(sm => sm.MenuCategories.Where(x => !x.IsDeleted))
.Where(sm => sm.StoreId == storeId && !sm.IsDeleted).ToList();
The scenario is I have a menu and Menu has multiple menu categories. Both menu and menu categories has a flag to mark items deleted. Now I want to retrieve only non-deleted menu along with NON-DELETED menu categories.
Create a subquery:
var result = _context.StoreMenus
.Where(sm => sm.StoreID == storeId && !sm.IsDeleted)
.Select(sm=>
new { Menu=sm, MenuCats = sm.MenuCategories.Where(smc => !smc.IsDeleted) })
.ToList();
Might want to have a look at something similar: here

mongodb c# combining set operations conditionally

I am looking for a way to conditionally combine Set operations. At the moment I have been unable to increment onto the updatedefinitions without having them consecutively dotted one after the other.
eg. instead of:
Builders<BsonDocument>.Update.Set("someElement.Length", b.Length)
.Set("someElement.Path", b.Path)
I am trying to get find a way to use something in the vain of:
var update = Builders<BsonDocument>.Update;
bool hasChanged = false;
if (a.Length != b.Length)
{
hasChanged = true;
update.Set("someElement.Length", b.Length)
}
if (a.Path != b.Path)
{
hasChanged = true;
update.Set("someElement.Path", b.Path)
}
if (hasChanged)
await someCollection.UpdateOneAsync(Builders<someModel>.Filter.Eq("_id", a.Id), update);
Is there a way of doing this or am I chasing a pie in the sky? I dont want to replace the entire document, and am looking to only update fields that have changed.
UpdateDefinition is an immutable object, so chaining operations on them keeps creating a new one each time. To do it conditionally, you need assign the result back to itself, just like LINQ.
update = update.Set(...);
If you maintain a collection of your conditionally created UpdateDefinitions, you can pass that collection into the Combine operator to create your final UpdateDefinition.
You can find an example on this similar question: C# MongoDB Driver - How to use UpdateDefinitionBuilder?

How do I disable some entities based on a few properties in NHibernate Search?

Im still pretty new to NHibernate.Search so please bear with me if this is stupid question :)
Say, I have indexed some entities of type BlogPost, which has a property called IsDeleted. If IsDeleted is set to true, I don't want my queries to show this particular blogpost.
Is this possible? And if it is - How? :P
Thanks in advance
- cwap
// Using NHibernate.Linq:
var result = Session.Linq<BlogPost>().Where(post => !post.IsDeleted).ToList();
// Using HQL:
var hql = "from BlogPost bp where bp.IsDeleted == false";
var result = Session.CreateQuery(hql).List<BlogPost>();
// Using Criteria API:
var result = s.CreateCriteria(typeof(BlogPost))
.Add(Restrictions.Eq("IsDeleted", false));
.List<BlogPost>();
NHibernate.Linq
HQL: Hibernate Query Language
Found the solution myself. I added the [Field(Index.Tokenized, Store = Store.Yes)]-attribute to the IsDeleted property, and added this clause to any query inbound:
string q = "(" + userQuery + ") AND IsDeleted:False";
I knew it was something simple :)