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.)
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…