Entity framework core EF Core在直接访问之前返回空关系

Entity framework core EF Core在直接访问之前返回空关系,entity-framework-core,lazy-loading,eager-loading,Entity Framework Core,Lazy Loading,Eager Loading,我有一些模型如下: public class Mutant { public long Id { get; set; } ... // Relations public long OriginalCodeId { get; set; } public virtual OriginalCode OriginalCode { get; set; } public int DifficultyLevelId { get; set; } publ

我有一些模型如下:

public class Mutant
{
    public long Id { get; set; }
    ...

    // Relations
    public long OriginalCodeId { get; set; }
    public virtual OriginalCode OriginalCode { get; set; }
    public int DifficultyLevelId { get; set; }
    public virtual DifficultyLevel DifficultyLevel { get; set; }
}

现在当我请求突变体时,原始代码为空:

但一旦我要求使用
原始代码
s,如下所示:

然后突变体的
OriginalCode
字段将不为空:


原因是什么?我如何修复它?

在EF核心文档的一节中解释了原因

第一种行为是因为EF Core目前不支持延迟加载,所以通常导航属性将获得
null
,直到您通过急切或显式加载专门加载它们。但是,快速加载部分包含以下内容:

提示
EntityFrameworkCore将自动修复以前加载到上下文实例中的任何其他实体的导航属性。因此,即使没有明确包含导航属性的数据,如果以前加载了部分或所有相关实体,也可能会填充该属性

这解释了为什么导航属性在第二种情况下不为null

现在,我不确定您想要修复这两个行为中的哪一个,因此我将尝试解决这两个问题

第一种行为可以通过使用当前可用的加载相关数据的方法之一“修复”,例如,即时加载:

var mutants = db.Mutants.Include(m => m.OriginalCode).ToList();
第二种行为是“设计的”,无法控制。如果要避免这种情况,请确保使用fresh new
DbContext
实例仅用于执行单个查询以重试所需的数据


更新:从v2.1开始,EF核心支持。但是,默认情况下它是不启用的,因此为了使用它,应该标记所有导航属性
virtual
,通过
UseLazyLoadingProxies
调用安装并启用它,或者使用-这两个都在EF核心文档中用示例进行了解释。

您可以猜到,我想要控制第一个行为。但仍然有一个大问题。你提到的这种方式,我应该明确指出需要填补的关系,是吗?确实如此。您必须使用多个
Include
/
然后使用Include
方法指定要“包括”的每个对象。好吧,有一些计划在将来自动完成,但现在这是唯一的选择。:)谢谢。非常有帮助的回答。现在EF核心支持延迟加载:虽然我认为没有设置为默认值,但这意味着它不是推荐的解决方案!我认为,如果使用正确,非惰性方法更难编写,但对于运行时更好,这将把许多未来的数据库请求放在一个数据库中。
        modelBuilder.Entity<Mutant>()
            .HasOne(m => m.OriginalCode)
            .WithMany(oc => oc.Mutants)
            .HasForeignKey(m => m.OriginalCodeId)
            .OnDelete(Microsoft.EntityFrameworkCore.Metadata.DeleteBehavior.Restrict);

        modelBuilder.Entity<Mutant>()
            .HasOne(m => m.DifficultyLevel)
            .WithMany(dl => dl.Mutants)
            .HasForeignKey(m => m.DifficultyLevelId)
            .OnDelete(Microsoft.EntityFrameworkCore.Metadata.DeleteBehavior.Restrict);
var mutants = db.Mutants.Include(m => m.OriginalCode).ToList();