dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.66k stars 3.16k forks source link

Problem with loading related entities after Select() #6325

Closed bartekkois closed 1 year ago

bartekkois commented 8 years ago

Hi Currently I am walking through one of ASP.NET tutorials and I`m trying to run it on ASP.NET Core (with EF Core). However there is a problem with one of LINQ queries like below. It should return a collection of Notification objects with Artist and Genre, but it returns only Notifications with Artis and Genre set to null (UserNotifications is a many-to-many relationship between Notifications and User; Notifications is related to Gig ang Gig to Artist).

var userId = User.FindFirst(ClaimTypes.NameIdentifier).Value;

            var notifications = _context.UserNotifications
                .Where(un => un.UserId == userId)
                .Select(un => un.Notification)
                .Include(g => g.Artist)
                .Include(g => g.Genre)
                .ToList();

Problem seems to be solved when I add the following query before:

            var notificationsTest = _context.Notifications  
                .Include(u => u.Gig).ThenInclude(u => u.Artist)  
                .ToList();

Why this happens and How can I put this in a single LINQ query in EF Core?

Further technical details

EF Core version: 1.0.0 Operating system: Windows 10 Visual Studio version: VS 2015 U3

gdoron commented 8 years ago

Select overrides Includes See this https://github.com/aspnet/EntityFramework/issues/6177#issuecomment-236229259 (I think it's very confusing and not intuitive, but that's how it works.)

bartekkois commented 8 years ago
  1. Does this change somehow from EF6 to EF Core, because according to tutorial this query should works on old EF?
  2. How should this query looks like to also return related entities?
gdoron commented 8 years ago

@bartekkois

  1. No idea, I used EF 6 only for a short while, and it was in a project with a crappy architecture and codebase.
  2. You already answered it in your issue, just remove the Select, use Include and ThenIncldue currently you can't traverse back the tree, so you need to start again:

    var notifications = _context.UserNotifications .Where(un => un.UserId == userId) .Include(un => un.Notification) .ThenInclude(g => g.Artist) .Include(un => un.Notification) .ThenInclude(g => g.Genre) .ToList();

p.s. I'm not a MS employee, you might want to wait for an official answer, but that's AFAIK the answer.

maumar commented 8 years ago

What @gdoron suggested is the correct workaround.

divega commented 8 years ago

@bartekkois I am going to mark this as an answered question, but:

  1. Feel free to re-open if the answer doesn't work.
  2. It would be great if you could point us to the exact tutorial page where you found something similar so that we can make sure that there is no bug in the tutorial.

FWIW, I don't think this query would have returned the related entities in EF6 either. In EF6 the paths passed to Include() have to represent valid navigation paths from the result type of the query.

bartekkois commented 8 years ago

I have found that exmaple in https://app.pluralsight.com/library/courses/full-stack-dot-net-developer/table-of-contents. Exactly two of them:

        var gigs = _context.Attendances
            .Where(u => u.AttendeeId == userId)
            .Select(a => a.Gig)
            .Include(a => a.Artist)
            .Include(g => g.Genre)
            .ToList();

        var notifications = _context.UserNotifications
            .Where(un => un.UserId == userId && un.IsRead == false)
            .Select(un => un.Notification)
            .Include(g => g.Gig.Artist)
            .ToList();

Moreover workround presented by @gdoron does not return Gig entities which are essential for this query.