EntityFramework - how to get rows that match any of the IDS from another table where the userId matches? - entity-framework

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

Related

How do you build a recursive Expression tree in Entity Framework Core?

We are using EFCore.SqlServer.HierarchyId to represent a hierarchy in our data.
My goal is to return the descendants of an object with a particular path of indeterminate length, e.g. given a tree with the hierarchy one->two->three->four, the path one/two/three would return four
Knowing the length of the path, I can make a query like this:
var collections = await context.Collections.Where(c => c.CollectionHierarchyid.IsDescendantOf(
context.Collections.FirstOrDefault(c1 => c1.FriendlyId == "three" &&
context.Collections.Any(c2 => c2.CollectionHierarchyid == c1.CollectionHierarchyid.GetAncestor(1) && c2.FriendlyId == "two" &&
context.Collections.Any(c3 => c3.CollectionHierarchyid == c2.CollectionHierarchyid.GetAncestor(1) && c3.FriendlyId == "one")
)
).CollectionHierarchyid
)).ToListAsync();
But how would you go about this if the length of the path is unknown? I can't call a recursive function from the expression because it won't compile from Linq to Entity Sql.
I know the answer lies somewhere in using System.Linq.Expressions to build the expression, but I am not sure where to start.
The problem can be solved without dynamic expression tree generation, at least not directly, but using standard LINQ query operators.
Let say you have a hierarchical entity like this
public class Entity
{
public HierarchyId Id { get; set; }
// other properties...
}
Given a subquery returning the full set
IQueryable<Entity> fullSet = context.Set<Entity>();
and subquery defining some filtered subset containing the desired ancestors
IQueryable<Entity> ancestors = ...;
Now getting all direct and indirect descendants can easily be achieved with
IQueryable<Entity> descendants = fullSet
.Where(d => ancestors.Any(a => d.Id.IsDescendantOf(a.Id));
So the question is how to build ancestors subquery dynamically.
Applying some filter to the full set and retrieving the direct ancestors filtered by another criteria can be done by using simple join operator
from p in fullSet.Where(condition1)
join c in fullSet.Where(condition2)
on p.Id equals c.Id.GetAncestor(1)
select c
Hence all you need is to apply that recursively, e.g. having
IEnumerable<TArg> args = ...;
representing the filtering criteria arguments ordered by level, then the query can be built as follows
var ancestors = args
.Select(arg => fullSet.Where(e => Predicate(e, arg)))
.Aggregate((prevSet, nextSet) =>
from p in prevSet join c in nextSet on p.Id equals c.Id.GetAncestor(1) select c);
With that being said, applying it to your example:
IEnumerable<string> friendlyIds = new [] { "one", "two", "three" };
var fullSet = context.Collections.AsQueryable();
var ancestors = friendlyIds
.Select(friendlyId => fullSet.Where(e => e.FriendlyId == friendlyId))
.Aggregate((prevSet, nextSet) =>
from p in prevSet join c in nextSet on p.CollectionHierarchyid equals c.CollectionHierarchyid.GetAncestor(1) select c);
var descendants = fullSet
.Where(d => ancestors.Any(a => d.CollectionHierarchyid.IsDescendantOf(a.CollectionHierarchyid));

Query Combinaton

I am trying to build a query using asp.net core c#
https://www.reflectionit.nl/blog/2017/paging-in-asp-net-core-mvc-and-entityframework-core
I trying to do a filtering however I need the data from another table which have my unique id
var result = _context.UserRoles.Where(y => y.RoleId.Contains(selectedRoles.Id)); // Retrieve the the userid i have from another table with the selected roleid
var query = _context.Users.Where(x => //I have already tried contains, where join );
If there is a site where i can learn this query please recommend. "Join()" does not work as I am doing paging
a least two solutions (please note that I do not check the identity classes members, so the following is the "spirit" of the solution (you miss the select clauses) ):
var result = _context.UserRoles.
Where(y => selectedRoles.Contains(y.RoleId)).
Select(y => y.User);
or
var result = _context.UserRoles.
Where(y => selectedRoles.Contains(y.RoleId)).
Select(y => y.UserId);
query = _context.Users.
Where(x => result.Contains(x.Id));
That said, assuming that there is no UserRoles table exposed in Identity (v2), you probably want:
userManager.Users.
Where(u => u.Roles.Any(r => selectecRoles.Contains(r.RoleId)));
Up to you to instanciate the userManager.

EF CORE Select distinct grandchildren with many-to-may relationship

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();

how to implement EF inner join with given filter?

SELECT DISTINCT k.* FROM [dbo].[kinds] K
INNER JOIN KindGraphic KG ON K.KindId = KG.KindId
INNER JOIN Graphics G ON KG.GraphicId = G.GraphicId
WHERE K.CategoryType = 2
AND G.IsSpecial = 1
How to write this in EF ? I am new to EF. I m using dbContex for my MVC project.
Make Note that "KindGraphic" table is mapped liked this ways
so I can not use this method https://stackoverflow.com/a/21986882/3264939
modelBuilder.Entity<Kind>()
.HasMany(c => c.Graphics)
.WithMany(g => g.Kinds)
.Map(t => t.MapLeftKey("KindId")
.MapRightKey("GraphicId")
.ToTable("KindGraphic"));
The result from your original query is some kind of complex result. So without selecting the exact columns (instead of using *), I assume the result is contained in an anonymous type like this:
{
Kind,
Graphic
}
I understand that KindGraphic is some kind of junction (join) table, so it's info is not important to include in the result (we can access KindId from Kind and GraphicId from Graphic). Here is the LINQ query:
var result = context.kinds.Where(e => e.CategoryType == 2)
.SelectMany(e=> e.Graphics.Where(g=>g.IsSpecial == 1),
(e, g) => new { Kind = e, Graphic = g} );
After your edit to use distinct, the query can be translated as you want all kinds having category type = 2 and any Graphics with IsSpecial = 1. So it should be like this:
var result = context.kinds.Where(e => e.CategoryType == 2 &&
e.Graphics.Any(g=>g.IsSpecial == 1));

Linq to Entities Select clause with lambda

I am working on a new project and we are using Entity Framework and the dev lead would like to use lambda queries whenever possible. One thing we are having a hard time figuring out is how to select two columns specifically. Also how to select distinct. We have a table that has multiple entries for a vendor but we want to just get a list of vendors and load to a dictionary object. It fails because as written it is trying to add a key value that has already been added. Take the following query.
Dictionary<int, string> dict = new Dictionary<int, string>();
dict = GetWamVendorInfo().AsEnumerable()
.Where(x => x.vendor_name != null && x.vendor_id != null)
//.Select(x => x.vendor_id).Distinct()
.Take(2)
.ToDictionary(o => int.Parse(o.vendor_id.ToString()), o => o.vendor_name);
What I would like to do is select just vendor_id and vendor_name so we can get just the distinct records.
Any help would be greatly appreciated.
Thanks,
Rhonda
Use an anonymous type:
// earlier bit of query
.Select(x => new { VendorId = x.vendor_id, VendorName = x.vendor_name } )
.Distinct()
.ToDictionary(o => o.VendorId, o => o.VendorName);
I've removed the call to Take(2) as it wasn't clear why you'd want it - and also removed the parsing of VendorId, which I would have expected to already be an integer type.
Note that you should almost certainly remove the AsEnumerable call from your query - currently you'll be fetching all the vendors and filtering with LINQ to Objects. There's also no point creating an empty dictionary and then ignoring it entirely. I suspect your complete query should be:
var vendors = GetWamVendorInfo()
.Select(x => new { VendorId = x.vendor_id,
VendorName = x.vendor_name } )
.Distinct()
.ToDictionary(o => o.VendorId,
o => o.VendorName);
As an aside, you should ask your dev lead why he wants to use lambda expressions (presumably as opposed to query expressions) everywhere. Different situations end up with more readable code using different syntax options - it's worth being flexible on this front.
Just use an anonymous object:
var vendors = GetWamVendorInfo().AsEnumerable()
.Where(x => x.vendor_name != null && x.vendor_id != null)
.Select(new {x.vendor_id, x.vendor_name})
.Take(2)
That's it. You can now work with vendors[0].vendor_id, vendors[0].vendor_name, and so on.