question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

EF Core doesn't lazy-load virtual navigation properties

See original GitHub issue

Issue: EF7 may not be lazy-loading all entities in a graph of related entities, despite all entities’ navigation properties being virtual:

I built a basic blog atop EF6. It behaves as expected and correctly models many-to-many relationships - in this case, the fact that posts may have zero or more authors.

I then rewrote this basic blog atop EF7.

This is where I found out that EF7 doesn’t currently support modelling many-to-many relationships (see #1368) and requires one to manually create and handle the join entity itself.

So, I added the PostAuthor type to the app’s model.

Aside: Many-to-many is going to be supported for RTW, right? This is a pretty essential feature

  +----------+          +----------+          +-------------+          +--------+
  |          | 1      n |          | 1      n |             | n      1 |        |
  |   Blog   | -------- |   Post   | -------- | PostAuthors | -------- | Author |
  |          |          |          |          |             |          |        |
  +----------+          +----------+          +-------------+          +--------+

When querying the model, I was found that EF wasn’t populating the Blog’s Posts collection requiring me to .Include(blog => b.Posts) and then didn’t populate the Post’s PostAuthors collection, requiring me to .ThenInclude(p=>p.PostAuthors). Imagine my surprise, then, when I also found that I had to .ThenInclude(pa=>pa.Authors). The net result? This:

 var blogs = ctx
        .Blogs
        .Include(b => b.Posts)
        .ThenInclude(p => p.PostAuthors)
        .ThenInclude(pa => pa.Author)
         .ToList();

My expectation is that since all the entities’ navigation properties are virtual (Post, PostAuthor and Author ) that they’d be lazy-loaded on demand.

What am I doing wrong here?

TIA,

Issue Analytics

  • State:closed
  • Created 8 years ago
  • Reactions:8
  • Comments:49 (14 by maintainers)

github_iconTop GitHub Comments

5reactions
JeffGillincommented, Dec 4, 2015

@divega, @rowanmiller First off, great job so far with EF7. The team is doing an excellent job. I know a major re-write of an ORM can’t be easy - to say the least. Regarding Lazy Loading, I feel it is absolutely essential. Here’s why. A lot of us have domain logic coded into model classes and use the repository pattern to fetch entities. In this case, the domain model class expects the navigation property to have values that match what’s in the database (whether they are loaded on-demand or eager loaded). Otherwise, for a particular operation in the domain model class, you are ‘assuming’ that the property was pre-loaded. This is a dangerous assumption. If it wasn’t pre-loaded, then in the case of a Collection, it’s Count will be 0, and your logic is assuming it’s zero in the database - but it’s not - it just wasn’t loaded. Thus, in order to work properly, you need to now coordinate each type of action in your application with a proper fetch strategy from your repository. I’m working with EF7 now, and whenever I load something from a repository, I pass in an enum value that represents a “eager loading strategy” enum parameter so that I can determine which navigation properties need to be included, and add then include those dynamically to the Linq-to-entities query. This works - but the necessary coordination between repository fetching and domain model action is definitely brittle. The lazy loading is a nice safe haven to ensure it will always be loaded when some logic is expecting it will be. EF6 had the ability to disable lazy loading. I’m going to suggest going the opposite direction with EF7. Make it a feature that is disabled by default but can be enabled via an option in the ‘DbContextOptionsBuilder’. One other note along the same lines, is that, with a clearly defined separation of layers (where domain model has no knowledge of EF), I’m finding it difficult to deal with collections in a way that works as I would expect. Let’s say a have a method in a model class that removes some child entities based on some filter. If I remove an entity from a ICollection navigation property, I would expect that this would automatically set a ‘deleted’ state on that child entity, and a ‘SaveChanges’ on the tracked parent entity will know to delete that item from the child table.
Since we want the domain model to be persistence ignorant, we don’t want any references to EF in the domain model assembly, and thus can’t directly set a deleted state with EF methods. In this type of architecture, it’s necessary that this removal is tracked (again - maybe an optional setting or something - but without it - my architecture, of keeping logic in domain model classes, no longer works and it’s necessary to start putting some of this logic in the service(application) layer which is undesirable because I want to write automated tests against the domain model to test it’s logic without having any db involved in the process. Is this something that’s possible to do? If so, is it something that is intended to be included at some point?

4reactions
rowanmillercommented, Dec 15, 2015

Lazy loading is not implemented in EF7 (backlog item is https://github.com/aspnet/EntityFramework/issues/3797).

When you query, you can use the Include method to bring in related data:

context.Users.Include(u => u.PersonalConfigData).Where(u => u.Username == username).Single()
Read more comments on GitHub >

github_iconTop Results From Across the Web

navigation property should be virtual - not required in ef ...
Update: an initial implementation of lazy loading, planned for EF Core 2.1, will require navigation properties to be declared virtual.
Read more >
Lazy Loading of Related Data - EF Core
EF Core will then enable lazy loading for any navigation property that can be overridden--that is, it must be virtual and on a...
Read more >
Lazy Loading With EF Core - NET Core Tutorials
First, EF Core by itself doesn't have lazy loading functionality out of the box. ... This is because all navigation properties must be...
Read more >
Loading Related Data - EF Core
Lazy loading means that the related data is transparently loaded from the database when the navigation property is accessed. Tip. You can view ......
Read more >
How do you manage non-loaded navigation properties in ...
Another use case for navigation properties in EF Core is to insert main and related entities without manually setting foreign keys (which you ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found