I'm using Entity Framework Core 2.1.2 with lazy loading enabled and am performing a query using AsNoTracking. I'm using Include to bring in my navigation property (a collection).
If all my entities have at least one child in their collection then it all works fine.
However, if any of my entities have no children then I get an error:
System.InvalidOperationException: Error generated for warning 'Microsoft.EntityFrameworkCore.Infrastructure.DetachedLazyLoadingWarning: An attempt was made to lazy-load navigation property 'Children' on detached entity of type 'ParentProxy'. Lazy-loading is not supported for detached entities or entities that are loaded with 'AsNoTracking()'.'
Here's a reproduction of the problem (it can be run from a console app after using NuGet to bring in Microsoft.EntityFrameworkCore 2.1.2, Microsoft.EntityFrameworkCore.Proxies 2.1.2, Microsoft.EntityFrameworkCore.InMemory 2.1.2):
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
namespace LazyLoadingIssue
{
public class Parent
{
public int Id { get; set; }
public string ParentName { get; set; }
public virtual ICollection<Child> Children { get; set; }
}
public class Child
{
public int Id { get; set; }
public int ParentId { get; set; }
public virtual Parent Parent { get; set; }
public string ChildName { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
SetupDatabase(setupToFail: true);
PerformTest();
Console.WriteLine("Press any key to finish");
Console.ReadLine();
}
private static void PerformTest()
{
using (var db = new MyContext())
{
try
{
IQueryable<Parent> parents = db.Rounds.Include(r => r.Children).AsNoTracking();
foreach (Parent parent in parents)
{
Console.WriteLine($"Parent (Id={parent.Id}) '{parent.ParentName}'");
foreach (Child child in parent.Children)
{
Console.WriteLine($" - Child (Id={child.Id}, ParentId={child.ParentId}) '{child.ChildName}'");
}
}
Console.WriteLine("** WORKED **");
}
catch (Exception ex)
{
Console.WriteLine("** FAILED **");
Console.WriteLine(ex);
}
}
}
private static void SetupDatabase(bool setupToFail)
{
using (var db = new MyContext())
{
db.Database.EnsureDeleted();
db.Database.EnsureCreated();
var parent1 = new Parent
{
ParentName = "First sample parent (has children)",
Children = new List<Child>
{
new Child {ChildName = "child-1"},
new Child {ChildName = "child-2"},
new Child {ChildName = "child-3"}
}
};
var parent2 = new Parent
{
ParentName = $"Second sample parent ({(setupToFail ? "with no children" : "has children")})",
Children = new List<Child>()
};
if (!setupToFail)
parent2.Children.Add(new Child {ChildName = "child-4"});
db.AddRange(parent1, parent2);
db.SaveChanges();
}
}
}
public class MyContext : DbContext
{
public DbSet<Parent> Rounds { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
// .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=_ModelApp;Trusted_Connection=True;Connect Timeout=5;ConnectRetryCount=0")
.UseInMemoryDatabase(databaseName: "_modelApp")
.UseLazyLoadingProxies()
;
}
}
}
Am I doing something wrong? Or is this a bug in EF Core? (I've posted an issue there too.)
We can disable lazy loading for a particular entity or a context. To turn off lazy loading for a particular property, do not make it virtual. To turn off lazy loading for all entities in the context, set its configuration property to false.
Lazy Loading vs. Eager Loading. While lazy loading delays the initialization of a resource, eager loading initializes or loads a resource as soon as the code is executed. Eager loading also involves pre-loading related entities referenced by a resource.
Lazy Loading vs. Eager Loading. Eager loading generates all web page content as soon as possible, while lazy loading delays the display of non-essential content. Lazy loading is a great option for large page files with more content.
EF Core will then enable lazy loading for any navigation property that can be overridden--that is, it must be virtual and on a class that can be inherited from. For example, in the following entities, the Post. Blog and Blog. Posts navigation properties will be lazy-loaded.
There's no bug. Since you are not tracking changes using .AsNoTracking, lazy loading will never work. You can use .Include("ChildEntity") in your query or give up of using .AsNoTracking.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With