The best way to order included entities in entity framework? - c#

What is the best practice to order the comment entity?
public async Task<IList<Post>> GetPosts() {
var posts = _context.Posts
.Include(u => u.User)
.ThenInclude(p => p.Photos)
.Include(c => c.Comments) <---- THIS
.OrderByDescending(p => p.Created)
.ToListAsync();
return await posts;
}

Before you return the posts, you can order the Comments attached to each post:
var posts = await _context.Posts
.Include(u => u.User)
.ThenInclude(p => p.Photos)
.Include(c => c.Comments)
.OrderByDescending(p => p.Created)
.ToListAsync();
foreach(var post in posts)
{
post.Comments = post.Comments
.OrderBy(comment => comment.DateCreated)
.ToList();
}
return posts;
I did the ordering above based on a property called DateCreated. You have to change this to the comment object property, on which you want to base the ordering.

Related

Why Where clause in not working with Virtual property in LINQ

I am trying to do something like this
var users = await _dbContext.Users.AsNoTracking().AsQueryable()
.Include(user => user.AdminRoles)
.Where(u => u.AdminRoles.Roles.Contains("admin2022"))
.ToListAsync();
Here the list is getting 0 results, but when I do
var users = (await _dbContext.Users.AsNoTracking().AsQueryable()
.Include(user => user.AdminRoles).ToListAsync())
.Where(u => u.AdminRoles.Roles.Contains("admin2022"))
.ToList();
Then it yields all the required results. Could some one please help me how can I make the first way work ?
Try:
var users = await _dbContext.Users
.AsNoTracking()
.AsQueryable()
.Include(user => user.AdminRoles.Where(x => x.Roles.Contains("admin2022")))
.ToListAsync();

EF Core Linq query containing Any cannot be translated [duplicate]

I have procedure which returns me entity's ids which I need.
(I decide to create this procedure, because entities which should be returned to the end user, are filtered by related entities, but EF Core does not support filtering by related entities).
Then I want to use this ids to get entities I need witch theirs related entities.
I'm using the Any operator. In my opinion it should generate query like this: WHERE id IN(1,2,3,4....)` but it seems it does not work like I want.
Instead, it returns warning with the information that the:
Any clause could not be translated and will be evaluated locally
How I could fix it?
My code below:
var assocsIds = await _context.Assoc.AsNoTracking()
.FromSql($"exec {SqlProcedures.GetAssocsForIndexProc} {query.IndexMviId}, {query.FilterByGroupId}")
.ToListAsync()
var productAssocs = await _context.Assoc
.Where(x => assocsIds.Any(z => z.Id == x.Id))
.Include(x => x.Attribute)
.ThenInclude(x => x.Translation)
.Include(x => x.Option)
.ThenInclude(x => x.Translation)
.Include(x => x.Mvi)
.ThenInclude(x => x.Translation)
.AsNoTracking()
.ToListAsync()
;
Can you first select "Id"s from assocsIds into another variable and then try the following?
var productAssocs = await _context.Assoc
.Where(x => yourIdsList.Contains(x.Id))
.Include(x => x.Attribute)
.ThenInclude(x => x.Translation)
.Include(x => x.Option)
.ThenInclude(x => x.Translation)
.Include(x => x.Mvi)
.ThenInclude(x => x.Translation)
.AsNoTracking()
.ToListAsync();

LINQ expression to filter

I have the following LINQ expression where I am fetching Courses, Students that belong to that Course, then the School's where the Student's goes to. The following LINQ expression works fine.
However, I need to further, filter it where I need to get Students with the City == 'Colarado'. How can I alter the following LINQ to my use case.
_dbContext.Courses
.Where(c => c.Id == Id)
.Include(c => c.Students)
.ThenInclude(c => c.Schools)
.OrderByDescending(c => c.Id)
.ToListAsync();
If you need all courses and only filter students - since EF Core 5.0 you can use filtered include:
_dbContext.Courses
.Where(c => c.Id == Id)
.Include(c => c.Students.Where(s => s.City == "Colarado"))
.ThenInclude(c => c.Schools)
.OrderByDescending(c => c.Id)
.ToListAsync();
You can do the filter in the Where method.
_dbContext.Courses
.Where(c => c.Id == Id && c.Students.All(s => s.City == "Colarado"))
.Include(c => c.Students)
.ThenInclude(c => c.Schools)
.OrderByDescending(c => c.Id)
.ToListAsync();

How to include multiple entities with one many-to-many in between

I have 3 tier entities. T <-> TI -> E also TI <- R (where <-> is m..n and -> 1..m)
I need to select a single T with the TI, E and R
without E it works:
var t = dbContext.T
.Include(i => i.TIs)
.ThenInclude(i => i.I)
.ThenInclude(i => i.R)
.Single(i => i.Id == id);
is it possible to include E without resorting to a for loop?
EDIT thanks to both answers from Canolyb and EspressoBins, although not exactly working, but pushed me to the right track. So the working code is:
var t = dbContext.T
.Include(i => i.TIs)
.ThenInclude(i => i.I)
.ThenInclude(i => i.R)
.Include(i => i.TIs)
.ThenInclude(i => i.I.Es)
.Single(i => i.Id == id);
I'm not sure if this is what you're looking for, but to the best of my knowlesge includes can be cascaded like this if you need two ThenIncludes on the same relation.
var t = dbContext.T
.Include(i => i.TIs)
.ThenInclude(i => i.I)
.Include(i => i.TIs)
.ThenInclude(i => i.R)
.Single(i => i.Id == id);
If this is not what you're looking for, it would benefit to see your Entity relations / fluent confiugation.
I had to look at some old code of mine with a similar problem to solve, and forgive me if my relationship directions aren't exact to yours, but does this help you get any closer?
Without using the .ThenInclude()
var result = dbContext.T
.Include(t => t.TI)
.Include(t => t.TI.E)
.Include(t => t.TI.R)
.Where(t => t.Id == id)
.Single();

Filtering in Linq with where condition

I want to get the users based on the continent for my application. I used the following code for this. Now I want to show all users if the continentId is null. How can I achieve this?
public async Task<IEnumerable<User>> GetUsersByContinent(int? continentId)
{
var users = await _context.Users
.Include(u => u.Country).ThenInclude(c => c.Continent)
.Where(u => u.Country.ContinentId == continentId)
.OrderBy(u => u.Username)
.ToListAsync();
return users;
}
You can use use method chaining to solve your problem.
public async Task<IEnumerable<User>> GetUsersByContinent(int? continentId)
{
var baseQuery= _context.Users.Include(u => u.Country).ThenInclude(c => c.Continent);
if (continentId.HasValue){
baseQuery = baseQuery.Where(u => u.Country.ContinentId == continentId)
}
return await baseQuery.OrderBy(u => u.Username).ToListAsync();
}
I would probably use #Jehof solution, but it's worth mentioning alternative solution.
.Where(u => continentId == null || u.Country.ContinentId == continentId)

Categories

Resources