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

Con*_*ver 21 entity-framework-core

我有一些类似下面的模型:

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; }
}
Run Code Online (Sandbox Code Playgroud)

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

    // Relations
    public virtual List<Mutant> Mutants { get; set; }
    public virtual List<OriginalCodeInputParameter> OriginalCodeInputParameters { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

在我的关系OnModelCreatingDBContext我做了这样的关系:

        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);
Run Code Online (Sandbox Code Playgroud)

现在当我请求Mutants时,OriginalCode为null:

Null OriginalCode

但是一旦我要求OriginalCode如下:

OriginalCodes

那么OriginalCode突变体的字段将不为空:

填充对象

是什么原因,我该如何解决?

Iva*_*oev 40

原因在EF Core文档的" 加载相关数据"部分中进行了解释.

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

提示
实体框架核心将自动将导航属性修复为先前加载到上下文实例中的任何其他实体.因此,即使您没有明确包含导航属性的数据,如果之前加载了部分或全部相关实体,仍可能会填充该属性.

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

现在,我不确定你想要解决这两种行为中的哪一种,所以将尝试解决这两种问题.

第一种行为可以通过使用当前可用的方法之一来加载相关数据来"固定",例如急切加载:

var mutants = db.Mutants.Include(m => m.OriginalCode).ToList();
Run Code Online (Sandbox Code Playgroud)

第二种行为是"按设计",无法控制.如果要避免它,请确保DbContext仅使用新的新实例执行单个查询以重试所需的数据.

更新:从v2.1开始,EF Core支持延迟加载.但是默认情况下它没有启用,因此为了使用它,应该标记所有导航属性virtual,安装Microsoft.EntityFrameworkCore.Proxies并通过UseLazyLoadingProxies调用启用它,或者使用不带代理的延迟加载 - 两者都用EF Core文档中的示例进行了解释.

  • 正如你可能猜到的,我想控制第一个行为。但还有一个大问题。你提到的这样,我应该明确地解决要填充的关系,对吗? (2认同)
  • 的确。您必须使用多个 `Include` / `ThenInclude` 方法来指定您想要“包含”的每一个。AFAIK 有一些计划在未来自动实现这一点,但目前这是唯一的选择。 (2认同)
  • 现在 EF Core 支持延迟加载:https://learn.microsoft.com/en-us/ef/core/querying/lated-data#lazy-loading (2认同)
  • 虽然我认为不设置为默认值,意味着它不是推荐的解决方案!我认为如果使用正确,非惰性方法更难编写,但更适合运行时,这会将许多未来的数据库请求集中在一起。 (2认同)

归档时间:

查看次数:

12806 次

最近记录:

6 年,6 月 前