51

Bowing to my Visual Studios request, I started my latest project using Entity Framework Core (1.0.1)

So writing my database models as I always have using the 'virtual' specifier to enable lazy loading for a List. Though when loading the parent table it appears that the child list never loads.

Parent Model

public class Events
{
    [Key]

    public int EventID { get; set; }
    public string EventName { get; set; }
    public virtual List<EventInclusions> EventInclusions { get; set; }
}

Child Model

public class EventInclusions
{
    [Key]
    public int EventIncSubID { get; set; }
    public string InclusionName { get; set; }
    public string InclusionDesc { get; set; }
    public Boolean InclusionActive { get; set; }

}

Adding new records to these tables seems to work as I am used to where I can nest the EventInclusions records as a List inside the Events record.

Though when I query this table

_context.Events.Where(e => e.EventName == "Test")

The Issue

EventInclusions will return a null value regardless of the data behind the scenes.

After reading a bit I am getting the feeling this is a change between EF6 which I normally use and EF Core

I could use some help in either making a blanket Lazy Loading on statement or figuring out the new format for specifying Lazy Loading.

Caz

Guillaume Jacquenot
  • 11,217
  • 6
  • 43
  • 49
Caz1224
  • 1,539
  • 1
  • 14
  • 37
  • Have you enabled lazy loading on the context? – Gusman Oct 19 '16 at 04:33
  • 1
    Hey Gusman, I had never needed to in EF6 - I am guessing that might be in the issue because I have nothing pertaining to Lazy Loading in my context – Caz1224 Oct 19 '16 at 04:35
  • If they've preserved the same mechanism (I still did not used EF with core) then you must set `Configuration.LazyLoadingEnabled = true;` and `Configuration.ProxyCreationEnabled = true;` on the context's constructor. – Gusman Oct 19 '16 at 04:40
  • 3
    EF Core does not currently support automatic lazy loading – Hamid Pourjam Oct 19 '16 at 04:41
  • Yep, dotctor is right: https://docs.efproject.net/en/latest/querying/related-data.html – Gusman Oct 19 '16 at 04:43
  • 3
    This is a good, but painful read... 100% regret the upgrade now! – Caz1224 Oct 19 '16 at 04:49

7 Answers7

41

Lazy loading is now available on EF Core 2.1 and here is link to the relevant docs:

https://learn.microsoft.com/en-us/ef/core/querying/related-data#lazy-loading

4b0
  • 21,981
  • 30
  • 95
  • 142
Elijah Lofgren
  • 1,437
  • 3
  • 23
  • 39
  • Is there an easy way to generate the ef models for lazy loading? Because it requires the navigation properties to be virtual... – juliushuck Dec 17 '18 at 12:15
  • 1
    Never mind. I can update the models from the database and it generated the navigation properties virtual. – juliushuck Dec 17 '18 at 15:32
  • 1
    how do you turn it off? – Christian Findlay May 25 '19 at 03:51
  • @MelbourneDeveloper, My understasnding is that lazy loading is off by default. If you're wanting more data to be loaded, I use .Include() calls to load the nested data that I need as shown here: https://learn.microsoft.com/en-us/ef/core/querying/related-data#eager-loading – Elijah Lofgren May 25 '19 at 21:13
  • @huckjulius were you able to generate the virtual navigation properties using `dotnet ef dbcontext scaffold` ? It's removing the virtual keyword for me. – Victor Mota Sep 27 '19 at 21:31
36

So it appears that EF Core does not currently support lazy loading. Its coming but may be a while off.

For now if anyone else comes across this problem and is struggling. Below is a demo of using Eager loading which is what for now you have to use.

Say before you had a person object and that object contained a List of Hats in another table.

Rather than writing

var person = _context.Person.Where(p=> p.id == id).ToList();

person.Hats.Where(h=> h.id == hat).ToList();

You need to write

var person = _context.Person.Include(p=> p.Hats).Where(p=> p.id == id).ToList();

And then person.Hats.Where(h=> h.id == hat).ToList(); will work

If you have multiple Lists - Chain the Includes

var person = _context.Person.Include(p=> p.Hats).Include(p=> p.Tickets)
                            .Include(p=> p.Smiles).Where(p=> p.id == id).ToList();

I kinda get why this method is safer, that your not loading huge data sets that could slow things down. But I hope they get Lazy loading back soon!!!

Caz

Michael Freidgeim
  • 26,542
  • 16
  • 152
  • 170
Caz1224
  • 1,539
  • 1
  • 14
  • 37
  • 7
    DO you have any idea how to implement repository pattern when I have to eager load the navigation properties? that is not easy at all when you have unknown number of `include` functions in need... any ideas? – Mohammed Noureldin Mar 05 '17 at 14:40
  • 1
    @MohammedNoureldin I ran into the same problem. In the end I 'solved' it by simply exposing the IQueryable. e.g. I now have things like a IQueryable GetByIdQueryable(string id) method on my repository. Callers can then do _repo.GetByIdQueryable(id) .Include(b => b.RelatedEntityProperty) .SingleOrDefault(); It works and is even okay with unit testing but to me it's a bit of a smell that you have to expose it this way. Another alternative would be to pass the string names of the properties you want to include but that's just asking for trouble imo. – Steve Aug 16 '17 at 18:47
  • And for multiple levels of includes ("also the Feathers on those Hats"), there is [.ThenInclude()](https://learn.microsoft.com/en-us/ef/core/querying/related-data#including-multiple-levels) – Hans Kesting Jul 27 '18 at 09:36
  • the include seems to consume a lot of time for big table. Maybe just forget about lazyloading after all. – nam vo Oct 20 '18 at 13:47
  • If Include is taking too much time, I would suggest looking at your database structure. If the DB is properly indexed and normalized it shouldn't be so bad. – Caz1224 Oct 21 '18 at 21:06
  • Outdated answer. Lazy-loading is supported by now. – Daniel Hillebrand Jan 22 '20 at 11:08
32

you can instaling this package for enable lazy loading in EF Core 2.1.

Microsoft.EntityFrameworkCore.Proxies

and then set this config in your ef dbContext

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
     => optionsBuilder
           .UseLazyLoadingProxies()
           .UseSqlServer("myConnectionString");

"Notice" this package works only on EF Core 2.1 and above.

Wingjam
  • 742
  • 8
  • 17
pejman
  • 740
  • 7
  • 13
12

For EF Core 2.1 and above,

Install:

 dotnet add package Microsoft.EntityFrameworkCore.Proxies --version 2.2.4 

Then Update your Startup.cs file as indicated below.

using Microsoft.EntityFrameworkCore.Proxies;



services.AddEntityFrameworkProxies();
services.AddDbContext<BlogDbContext>(options =>
            {
                options.UseSqlite(Configuration.GetSection("ConnectionStrings")["DefaultConnection"]);
                options.UseLazyLoadingProxies(true);
            });
Kowi
  • 211
  • 3
  • 6
  • This looked helpful so I tried it, but it doesn't work. I think that Lazy Loading cannot be turned off in EF Core: https://github.com/aspnet/EntityFrameworkCore/issues/15802 – Christian Findlay May 25 '19 at 03:51
  • options.UseLazyLoadingProxies(false); disabled LazyLoading on my machine. – Kowi May 28 '19 at 17:48
7

There's a pre-release version that just came out, regardless it's supposed to be available in full release soon.

A couple of caveats:

  • All your data properties that are more than simple types (ie: any other classes/tables) need to be public virtuals (default scaffolding they're not).
  • This line gets tucked into OnConfiguring on your data context:

        optionsBuilder.UseLazyLoadingProxies();
    
  • It's (currently) pre-release so may the force be with you.
Eric
  • 2,273
  • 2
  • 29
  • 44
5

LazyLoading is not yet supported by EF Core, but there is a non-official library that enables LazyLoading: https://github.com/darxis/EntityFramework.LazyLoading. You can use it until it is officially supported. It supports EF Core v1.1.1. It is available as a nuget package: https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.LazyLoading/

Disclaimer: I am the owner of this repo and invite you to try it out, report issues and/or contribute.

Darxis
  • 1,482
  • 1
  • 17
  • 37
3

Lazy load is planned to be in EF core 2.1 - you can read more on why it is a must-have feature - here.

baHI
  • 1,510
  • 15
  • 20
  • Link broken and when fixed requires login. Is there a publicly available source? – Isaac Llopis Sep 04 '17 at 12:18
  • Link fixed :D Thanx for letting me know. Once the lazy load gets to EF7, it'll be usable...waiting for that for almost a year... – baHI Sep 08 '17 at 18:46
  • I tried it, and find it too slow, so it's better to skip the lazy loading after all. https://wildermuth.com/2018/07/28/Avoid-Lazy-Loading-in-ASP-NET – nam vo Oct 20 '18 at 13:50
  • it's how you use it. lazy loading and n+1 select is a common issue. would avoid it if we know in advance what we need. the big issue with EF core before the support of lazy load was that it was not able to tell if you have a null value or just a non-loaded n:1 reference (missing proxy, no datanotloadedexception). it's like with bycicles, just because you use a car, does not mean someone other should not ever ride a bike. – baHI Oct 22 '18 at 06:54