18

There are plenty of posts about how to disable lazy loading in Entity Framework, but the same techniques don't work in EF Core. I found the LazyLoadingEnabled property in the change tracker, but this doesn't seem to work at all.

Everything points to this in EF:

this.Configuration.LazyLoadingEnabled = false;

But, the Configuration property is missing in EF Core.

Here is an example of what I am talking about:

public class TestContext : DbContext
{
    public DbSet<Person> People { get; set; }
    public DbSet<Address> Addresses { get; set; }

    public TestContext()
    {
        this.ChangeTracker.LazyLoadingEnabled = false;
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {            
        var connection = new SqliteConnection($"Data Source=Test.db");
        connection.Open();

        var command = connection.CreateCommand();

        command.CommandText = $"PRAGMA foreign_keys = ON;";
        command.ExecuteNonQuery();

        optionsBuilder.UseSqlite(connection);
        optionsBuilder.UseLazyLoadingProxies(false);

        base.OnConfiguring(optionsBuilder);
    }

    private static void Main(string[] args)
    {
        Console.WriteLine("Hello World!");

        using (var context = new TestContext())
        {
            context.Database.EnsureCreated();

            var personKey = Guid.NewGuid().ToString();
            var addressKey = Guid.NewGuid().ToString();

            context.People.Add(new Entities.Person { PersonKey = personKey, BillingAddress = new Entities.Address { AddressKey = addressKey } });
            context.SaveChanges();
        }

        using (var context = new TestContext())
        {
            var people = context.People.ToList();

            foreach (var person in people)
            {
                if (person.BillingAddress == null) throw new Exception("The billing address wasn't loaded");
            }
        }
    }
}

The above throws an exception because BillingAddress is not getting loaded even though I turned lazy loading off.

I suspect this is a bug, but please tell me it isn't. I logged it here: https://github.com/aspnet/EntityFrameworkCore/issues/15802

You can download the sample here: https://www.dropbox.com/s/mimvgvcmibr7em2/EFSQLiteTest.7z?dl=0

d219
  • 2,707
  • 5
  • 31
  • 36
Christian Findlay
  • 6,770
  • 5
  • 51
  • 103
  • 3
    There seems to be some confusion about what lazy loading *off* means. When the lazy loading is *off*, then EF Core *won't* load automatically related data - you have to explicitly do that using either eager or explicit loading. So the exception is expected and proves that EF Core does what it is supposed to do. In order to let EF Core load the related data automatically on first access of a navigation property, you need to do the opposite - turn the lazy loading *on*. – Ivan Stoev May 25 '19 at 07:46
  • I've tried both, but neither load the BillingAddress. There is no way to load all child entities without extreme hacks. – Christian Findlay May 25 '19 at 07:55
  • I don't want Lazy Loading. I want to load all entities right at the start. – Christian Findlay May 25 '19 at 07:55
  • Disabling lazy loading won't do that. It doesn't mean "load everything automatically". Such option still doesn't exist, so my answer https://stackoverflow.com/questions/49593482/entity-framework-core-2-0-1-eager-loading-on-all-nested-related-entities/49597502#49597502 still applies. – Ivan Stoev May 25 '19 at 07:58
  • Thanks. Yes. I'm using your workaround. It is great. But, we shouldn't have to use crazy workarounds like that. EF should just load all the data. – Christian Findlay May 25 '19 at 08:02
  • That's true. But the point is that such option is missing (most likely due to their priorities, time and resources). Lazy loading is different type of functionality which also was missing in earlier versions, but it's not a replacement of the feature you need. And `true` / `false` is not enough for controlling such feature when (and if) implemented, because would need at least 3 options - something like `LoadBehavior` - `None`, `Lazy`, Auto`. Anyway, to recap - `LazyLoading == false` is not a bug and works as expected. – Ivan Stoev May 25 '19 at 08:16
  • @IvanStoev I don't think your workaround works recursively does it? – Christian Findlay May 25 '19 at 08:26
  • @IvanStoev what bothers me is that a data layer should just load all data by default, and if there are performance issues, you should be able to use lazy loading, or choose to exclude some data. EF seems to have it backwards. – Christian Findlay May 25 '19 at 08:27
  • Such functionality don't exist in EF(6), not sure about other ORMs like NHibernate. And yes, my workaround works recursively. – Ivan Stoev May 25 '19 at 08:37
  • It does exist. It just doesn't work in EF core. – Christian Findlay May 25 '19 at 08:39
  • 3
    Eagerly loading all related data is rarely what you'll want; most of the times you'll just pull your entire database into local memory. Keep in mind that each navigation property access is another (LEFT OUTER) join, which will make the queries very slow as well as materialization due to the sheer amount of rows and columns returned. Frankly, I don't think such functionality should exist, and if the EF team plans it, it should require weird hacks. You seem to be confused about what is lazy loading and what is eager loading, you should probably read up on that. – DevilSuichiro May 25 '19 at 16:08
  • @ChristianFindlay your expectation is the polar opposite of the actual implementation. Take our word for it, we've been collectively burned before. Eager loading should _ALWAYS_ be done through explicit _Include_ and _projections_ that way the default implementation is efficient by default and less likely to end in loading the entire database into memory. It sounds like you actually _want_ lazy loading, or you want the compiler to parse all possible outcomes in your code to determine what properties and records to load into memory, that is just lazy programming – Chris Schaller Jan 04 '22 at 08:43

1 Answers1

32

If your problem is how to disable LazyLoading with EF Core try:

this.ChangeTracker.LazyLoadingEnabled = false;
d219
  • 2,707
  • 5
  • 31
  • 36
  • 1
    Worked for me to temporarily disable lazy loading when using table by hierarchy; I was getting a "An attempt was made to lazy-load navigation property..." – Jeff Dec 17 '19 at 03:38
  • 1
    Since Lazy Loading is enabled at startup time / config time, I was lead to believe this flag didn't exist any more. Thank you so much for correcting my mistake!! – pbristow May 06 '21 at 21:42