I've got an EDM with two tables Product and ProductCategory with a many-to-many relationship between both.
What I'm currently trying to do is to build a dynamic query to select the products related to the categories the user has selected through the UI.
In short I should build a query like the following but based one or more categories that I don't know at compile time.
var productQuery = context.Product.Where
(p => p.ProductCategories.Any(c => c.CategoryId == id1 ||
c.CategoryId == id2 || ...));
I've read a lot of things and I'm actually very new to linq so I really don't know where to start.
What is the best approach to do such queries ?
Thank you for your time.
var ids = new [] { id1, id2, // ...
var productQuery = context.Product.Where(
p => p.ProductCategories.Any(c => ids.Contains(c.CategoryId)));
Related
I have categories, and categories have a collection of products (Category.Products). I need to retrieve a category from the db by its id, but instead of including all its products, I want it to only include products with a given condition (example, order=0)
How can I do this with linq?
I tried with:
var e = db.Categories
.Include(a => a.products)
.Where(a => a.products.Any(r => r.order == 0))
.FirstOrDefault(p => p.id == id_category);
I don't think you can do that. In any case, the call to .Include() should be after any where clause, or it won't work.
In order to filter child collection you can try to select that to YouCustomModelor anonymous projection.
Note that it is not currently possible to filter which related entities are loaded. Include will always bring in all related entities Msdn reference.
var e = db.Categories
.Where(c => c.id == id_category)
.Select(p=> new
{
category = p,
products = p.Products.Where(k=>k.order==0)
}.FirstOrDefault();
var e = db.Categories.Where(a => a.order == 0);
I'm trying to learn EF Core and hit this wall since I'm also fairly new to LINQ
Consider the model:
I'm trying to get all the distinct users from a single company;
The SQL statement would be something like this:
SELECT DISTINCT gau.AppUserId, au.Name, au.Id FROM Companies c
INNER JOIN Groups g ON g.CompanyId = c.Id
INNER JOIN GroupAppUsers gau ON gau.GroupId = g.Id
INNER JOIN AppUsers au ON gau.AppUserId = au.Id
Where c.Id = 40
Result:
How would I build this query like this? (Without the includes)
return await context.Companies
.Include(g => g.Groups)
.ThenInclude(au => au.AppUsers)
.ThenInclude(u => u.AppUser)
.SingleOrDefaultAsync(x => x.Id == id);
*Also, I'm not sure about the DB Model, I'm trying to avoid circular references but I think I should put Users linked with Companies instead of Groups, what do you think??
I'm trying to get all the distinct users from a single company
Rather than starting from companies and navigating to users, thus multiplying the users due to many-to-many relationship and then applying Disctinct operator, you could simply start from users and apply Any based criteria, thus eliminating the need of Disctinct at all.
Something like this (the DbSet / navigation property names could be different):
var companyUsers = await context.Users
.Where(u => u.UserGroups.Any(ug => ug.Group.Company.Id == id))
.ToListAsync();
Assuming your linking table (GroupAppUser) isn't modeled as an entity, something like:
var q = from c in db.Companies
from g in c.Groups
from u in g.AppUsers
select u;
or in Lambda form:
var q = db.Companies
.SelectMany(c => c.Groups)
.SelectMany(g => g.AppUsers);
Once you have the single Companies object, you can use the Navigation properties to get the AppUser objects:
return await context.Companies
.Include(g => g.Groups)
.ThenInclude(au => au.AppUsers)
.ThenInclude(u => u.AppUser)
.SingleOrDefaultAsync(x => x.Id == id)
.Groups.AppUsers.Distinct();
For instance, I have a query:
SELECT * FROM
persons
LEFT JOIN vehicles
ON persons.Id = vehicles.OwnerId
I would like execute this query on an EF data context and have array of pairs "person-vehicle". how do I do it?
Another example:
SELECT persons.*, COUNT(vehicles.*) as cnt FROM
persons
JOIN vehicles
ON persons.Id = vehicles.OwnerId
GROUP BY vehicles.Id
Here I want to have a dictionary of a person as a key and number of vehicles he owns as a value.
I know that these quesies are simple enough and it's better to avoid raw sql in these cases. But I want to know possibilities of raw query handling, because real life queries can be much more complex.
You probably want to do some reading ion LINQ to Entities. https://msdn.microsoft.com/en-us/library/vstudio/bb386964(v=vs.100).aspx
The first one is pretty basic:
var persons = context.Persons
.Include(p => p.Vehicles)
.ToList();
The second one is a little more advanced:
var persons = context.Persons
.Select(p => new { Person p, VehicleCount = p.Vehicles.Count() }
.ToList();
You could also do a group by which is described in the link.
I'm not sure how to get the rows I need in EF. In SQL it would look something like this:
SELECT * FROM [Recipes]
JOIN [UserFavorites] ON [UserFavorites].[RecipeId] = [Recipes].[Id]
WHERE [UserFavorites].[UserId] = #UserId
I know how to get the userfavorites that match the user id like this:
db.UserFavorites.Where(x => x.UserId == userId
But then how do I get all of the recipes that match the recipeIds inside of those userfavorites?
You can either use LINQ and construct a query:
var recipes = from r in db.Recipes
join f in db.UserFavorites on r.Id equals f.RecipeId
where f.UserId = userId
select r
or you can use the lambda syntax with navigation properties, assuming you have them set up for the relationships in question
var recipes = db.Recipes.Where(r => r.UserFavorites.Any(f => f.UserId == userId));
You can, of course, construct the actual query that's described in the first section using the equivalent lambda syntax (since the query syntax is just a language feature that compiles down to the equivalent calls to the extension methods using anonymous delegates), but that tends to be a little more difficult to read.
How about:
var recipes = context.Recipes
.SelectMany(r => r.Users, (r, u) => new { Recipe = r, User = u }
.Where(o => o.User.UserId = userId)
.Select(o => o.Recipe);
This implies UserFavorites is the intersection table between Recipes and Users
Recipes >- UserFavorites -< Users
I have a many to many relationship in EF4 with the following entities:
[Student] - [Class] - [Student_Class]
Moreover i have a [School] entity with a FK on [Student].
If i want to have all the Students of my school i do:
context.School.Include("Student")
but if i want to have the 1rst class of my Students in my school ?
context.School.Include("Student").Include("Student_Class").Where(...
i did not manage to make this thing work...
Can you help ?
Also is it more intelligent to write a full Linq select?
Thanks
John
If you want to do a conditional eager load, then you should NOT be using the Include method.
For loading your school object containing only the students that belong to the first class
You can do a Filtered Projection which returns an Anonymous Type object:
var school = context.School
.Where(s => s.SchoolID == 1) // or any other predicate
.Select(s => new
{
School = s,
Students = s.Student.Where(st => st.ClassID == 1)
}).ToList();
Another way would be to Leverage Attach Method which returns EntityObject:
var school = context.School.Where(s => s.SchoolID == 1).First()
var sourceQuery = school.Students.CreateSourceQuery()
.Where(st => st.ClassID == 1);
school.Students.Attach(sourceQuery);
For a more detailed discussion about this, you can also check:
Entity Framework: How to query data in a Navigation property table