尽管急于获取,但仍"attempt was made to lazy-load navigation property on detached entity"



我正在使用启用了延迟加载的实体框架核心 2.1.2,并使用 AsNoTracking 执行查询。我正在使用"包含"来引入我的导航属性(集合(。

如果我的所有实体的集合中至少有一个子项,那么一切正常。

但是,如果我的任何实体没有子实体,则会出现错误:

系统无效操作异常:生成警告错误 'Microsoft.EntityFrameworkCore.Infrastructure.DetachedLazyLoadWarning: 尝试在 上延迟加载导航属性"子项" 类型为"父代理"的分离实体。不支持延迟加载 对于分离的实体或加载了 'AsNoTracking(('.">

下面是该问题的重现(在使用 NuGet 引入 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()
;
}
}
}

我做错了什么吗?或者这是 EF Core 中的错误?(我也在那里发布了一个问题。

对于后代,下面是 EF Core 团队的响应:

这是因为 NoTracking 查询不支持延迟加载 (#10042( 但是如果它看起来像,我们尽量不让它扔掉 不需要延迟加载。回想起来,最好 总是扔。请注意,警告可以配置为不抛出 在 DbContextOptionsBuilder 中使用 ConfigureWarnings。

以防万一它对某人有用,我最终做的是创建第二个"ReadOnlyRepository",配置为不使用延迟加载并始终返回未跟踪的集。我将此存储库用于查询,在这些查询中,我永远不会保留对任何实体的更改,结果集可能很大,并且需要执行良好。

public class ReadOnlyRepository : MainDbContextBase, IReadOnlyRepository
{
public ReadOnlyRepository(IConfigurationSettings configurationSettings)
: base(configurationSettings, false)
{
}
public IQueryable<T> Retrieve<T>() where T : class, IAmAnAggregateRoot
{
return GetDbSet<T>().AsNoTracking();
}
}
public class MainDbContextBase : DbContext
{
private readonly IConfigurationSettings configurationSettings;
private readonly bool useLazyLoading;
protected MainDbContextBase(IConfigurationSettings configurationSettings, bool useLazyLoading)
{
this.configurationSettings = configurationSettings;
this.useLazyLoading = useLazyLoading;
}
protected DbSet<T> GetDbSet<T>() where T : class
{
return Set<T>();
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder
.UseLazyLoadingProxies(useLazyLoading)
.UseSqlServer(configurationSettings.ConnectionString);
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
...
}
}

}

没有错误。 由于您没有使用 跟踪更改。由于没有跟踪,延迟加载将永远不起作用。 您可以使用 .在查询中包含("子实体"(或放弃使用 .作为无跟踪。

最新更新