0

I have this query below that fetches all these children entities (ex. PracticedStyles, ReceivedReviews, InstructedPoses, etc)

All I need is the .count() for these children collections.

Question - Is there a faster way to run this query to get the counts for these includes, then using this query below? The run time is ~4-7 seconds and this is with very little data in the DB.

var userWithChildren = await _dbContext.Users
        .Include(p => p.Yogabands.Where(p => p.IsActive == true))
        .Include(p => p.PracticedStyles)
        .Include(p => p.PracticedPoses)
        .Include(p => p.ReceivedReviews)
        .Include(p => p.InstructedStyles)
        .Include(p => p.InstructedPoses)
        .Include(p => p.InstructorPrograms)
        .FirstOrDefaultAsync(user => user.UserName == userName);
chuckd
  • 13,460
  • 29
  • 152
  • 331
  • Not the answer but a suggestion, use Dapper and execute raw sql instead. – Zafor Nov 04 '21 at 03:42
  • 2
    If all you need is the count, then select that `.Select(p => new { user = p, PracticedStylesCount = p.PracticedStyles.Count(), ...}`. The core problem is that you are fetching `count1 * count2 * count3 * ...` rows from the database. – Jeremy Lakeman Nov 04 '21 at 03:45
  • Hi Jeremy, can you please provide an example as an answer? – chuckd Nov 04 '21 at 03:53

1 Answers1

4

Absolutely there is. Include is a blunt instrument which returns every row on the join. Worse still, because of the way SQL operates you get the results back in a normalized form, meaning that the total number of rows returned is all of those counts you're after multiplied together. With as many Includes as you have this could be tens of thousands of rows.

What you want is a projection, something like this:

var userWithChildren = await _dbContext.Users
    .Select(p => new
    {
        user = p,
        YogaBandCount = p.Yogabands.Where(yb => yb.IsActive == true).Count(),
        PracticedStylesCount = p.PracticedStyles.Count(),
        PracticedPosesCount = p.PracticedPoses.Count()
        ReceivedReviewsCount = p.ReceivedReviews.Count(),
        InstructedStylesCount = p.InstructedStyles.Count(),
        InstructedPosesCount = p.InstructedPoses.Count()
        InstructorProgramsCount = p.InstructorPrograms.Count()
    })
    .FirstOrDefaultAsync(p => p.user.UserName == userName);

This will create an anonymous class which has the user on it as well as all the counts you need.

Turksarama
  • 1,136
  • 6
  • 13
  • Hi Turksarama. Thanks for the help! Do you know if I can apply projection to the Specification pattern with the unit of work and generic repo patterns. I have a post here https://stackoverflow.com/questions/69792580/fetching-the-count-of-child-entities-with-ef-core-instead-of-the-full-entity-usi asking for help. – chuckd Nov 04 '21 at 04:02
  • 1
    In general my advice with EF is to not use the repository pattern at all. Your `DBContext` is _already_ a repository, there is no need to duplicate its functionality. The same goes with your specification, you are effectively repeating the functionality already given to you by `IQueryable`. Why are you doing this? What problem are you trying to solve? Don't use a pattern "just because". – Turksarama Nov 04 '21 at 05:50
  • Hi Turksarama. I followed this guy here https://github.com/TryCatchLearn for both his 2 projects (Skinet3.1, Dating App) which he had created videos on Udemy that I watched. After watching him use all these patterns in his projects it made sense to use them (Generic Repo, unit of work, specification), but know I'm not so sure. – chuckd Nov 04 '21 at 15:09
  • If you're going to use a pattern you should understand why to use it and not just copy blindly. Do some more research on these patterns to find what kind of problems they're meant to solve before deciding to use them. The repository pattern in particular is commonly used with Entity Framework, but I fundamentally disagree on it's use with it. – Turksarama Nov 04 '21 at 22:54
  • I've found a good article here that explains my position on the repository pattern with EF: https://www.thereformedprogrammer.net/is-the-repository-pattern-useful-with-entity-framework-core/ – Turksarama Nov 05 '21 at 05:09