Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EF Core returns null relations until direct access

I have some models like those below:

public class Mutant {     public long Id { get; set; }     ...      // Relations     public long OriginalCodeId { get; set; }     public virtual OriginalCode OriginalCode { get; set; }     public int DifficultyLevelId { get; set; }     public virtual DifficultyLevel DifficultyLevel { get; set; } } 

and

public class OriginalCode {     public long Id { get; set; }     ...      // Relations     public virtual List<Mutant> Mutants { get; set; }     public virtual List<OriginalCodeInputParameter> OriginalCodeInputParameters { get; set; } } 

and in the OnModelCreating of DBContext I made the relations like these:

        modelBuilder.Entity<Mutant>()             .HasOne(m => m.OriginalCode)             .WithMany(oc => oc.Mutants)             .HasForeignKey(m => m.OriginalCodeId)             .OnDelete(Microsoft.EntityFrameworkCore.Metadata.DeleteBehavior.Restrict);          modelBuilder.Entity<Mutant>()             .HasOne(m => m.DifficultyLevel)             .WithMany(dl => dl.Mutants)             .HasForeignKey(m => m.DifficultyLevelId)             .OnDelete(Microsoft.EntityFrameworkCore.Metadata.DeleteBehavior.Restrict); 

now when I request for Mutants, the OriginalCode is null:

Null OriginalCode

but as soon as I request for OriginalCodes like below:

OriginalCodes

then the OriginalCode field of the mutants will be not null:

Filled Object

What is the reason and how could I fix it?

like image 714
ConductedClever Avatar asked Feb 19 '17 13:02

ConductedClever


People also ask

Should I use EF6 or EF core?

Keep using EF6 if the data access code is stable and not likely to evolve or need new features. Port to EF Core if the data access code is evolving or if the app needs new features only available in EF Core. Porting to EF Core is also often done for performance.

What is lazy loading EF core?

Lazy loading means that the related data is transparently loaded from the database when the navigation property is accessed.

Does EF core cache query results?

It's important to clarify that EF Core already automatically compiles and caches your queries using a hashed representation of the query expression. When your code needs to reuse a previously executed query, EF Core uses the hash to lookup and return the compiled query from the cache.

Is EF core faster than EF6?

The conclusions are obvious: in almost every test conducted by Chad, Entity Framework Core 3 is faster than Entity Framework 6 – exactly 2.25 to 4.15 times faster! So if performance is important to your application and it operates on large amounts of data, EF Core should be a natural choice.


1 Answers

The reason is explained in the Loading Related Data section of the EF Core documentation.

The first behavior is because EF Core currently does not support lazy loading, so normally you'll get null for navigation properties until you specifically load them via eager or explicit loading. However, the Eager loading section contains the following:

Tip
Entity Framework Core will automatically fix-up navigation properties to any other entities that were previously loaded into the context instance. So even if you don't explicitly include the data for a navigation property, the property may still be populated if some or all of the related entities were previously loaded.

which explains why the navigation property is not null in the second case.

Now, I'm not sure which of the two behaviors do you want to fix, so will try to address both.

The first behavior can be "fixed" by using one of the currently available methods for loading related data, for instance eager loading:

var mutants = db.Mutants.Include(m => m.OriginalCode).ToList(); 

The second behavior is "by design" and cannot be controlled. If you want to avoid it, make sure to use fresh new DbContext instance just for executing a single query to retry the data needed.

Update: Starting with v2.1, EF Core supports Lazy Loading. However it's not enabled by default, so in order to utilize it one should mark all navigation properties virtual, install Microsoft.EntityFrameworkCore.Proxies and enable it via UseLazyLoadingProxies call, or utilize Lazy-loading without proxies - both explained with examples in the EF Core documentation.

like image 184
Ivan Stoev Avatar answered Sep 24 '22 16:09

Ivan Stoev