EF Core returns 空关系,直到直接访问
EF Core returns null relations until direct access
我有一些像下面这样的模型:
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; }
}
和
public class OriginalCode
{
public long Id { get; set; }
...
// Relations
public virtual List<Mutant> Mutants { get; set; }
public virtual List<OriginalCodeInputParameter> OriginalCodeInputParameters { get; set; }
}
在 DBContext
的 OnModelCreating
中,我建立了如下关系:
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);
现在当我请求 Mutants 时,OriginalCode 为空:
但是一旦我请求 OriginalCode
如下:
那么突变体的OriginalCode
字段将不为空:
这是什么原因,我该如何解决?
原因在 EF Core 文档的 Loading Related Data 部分进行了解释。
第一个行为是因为 EF Core 当前不支持延迟加载,因此通常您会获得 null
导航属性,直到您通过预先加载或显式加载专门加载它们。但是,预加载 部分包含以下内容:
Tip
Entity Framework Core will automatically fix-up navigation properties to any other entities that were previously loaded into the context instance. So even if you don't explicitly include the data for a navigation property, the property may still be populated if some or all of the related entities were previously loaded.
这解释了为什么在第二种情况下导航 属性 不为空。
现在,我不确定您想修复这两种行为中的哪一种,所以会尝试解决这两种行为。
第一个行为可以是 "fixed" 通过使用当前可用的方法之一来加载相关数据,例如预先加载:
var mutants = db.Mutants.Include(m => m.OriginalCode).ToList();
第二种行为是"by design",无法控制。如果你想避免它,请确保使用全新的 DbContext
实例来执行单个查询以重试所需的数据。
更新: 从 v2.1 开始,EF Core 支持 Lazy Loading. However it's not enabled by default, so in order to utilize it one should mark all navigation properties virtual
, install Microsoft.EntityFrameworkCore.Proxies and enable it via UseLazyLoadingProxies
call, or utilize Lazy-loading without proxies - 两者都在 EF Core 文档中用示例进行了解释。
使用包管理器控制台安装Microsoft.EntityFrameworkCore.Proxies
install-package Microsoft.EntityFrameworkCore.Proxies
然后在您的上下文中 class 添加 .UseLazyLoadingProxies()
:
namespace SomeAPI.EFModels
{
public partial class SomeContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder
.UseLazyLoadingProxies()
.UseSqlServer(connectionString);
}
}
}
}
我有一些像下面这样的模型:
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; }
}
和
public class OriginalCode
{
public long Id { get; set; }
...
// Relations
public virtual List<Mutant> Mutants { get; set; }
public virtual List<OriginalCodeInputParameter> OriginalCodeInputParameters { get; set; }
}
在 DBContext
的 OnModelCreating
中,我建立了如下关系:
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);
现在当我请求 Mutants 时,OriginalCode 为空:
但是一旦我请求 OriginalCode
如下:
那么突变体的OriginalCode
字段将不为空:
这是什么原因,我该如何解决?
原因在 EF Core 文档的 Loading Related Data 部分进行了解释。
第一个行为是因为 EF Core 当前不支持延迟加载,因此通常您会获得 null
导航属性,直到您通过预先加载或显式加载专门加载它们。但是,预加载 部分包含以下内容:
Tip
Entity Framework Core will automatically fix-up navigation properties to any other entities that were previously loaded into the context instance. So even if you don't explicitly include the data for a navigation property, the property may still be populated if some or all of the related entities were previously loaded.
这解释了为什么在第二种情况下导航 属性 不为空。
现在,我不确定您想修复这两种行为中的哪一种,所以会尝试解决这两种行为。
第一个行为可以是 "fixed" 通过使用当前可用的方法之一来加载相关数据,例如预先加载:
var mutants = db.Mutants.Include(m => m.OriginalCode).ToList();
第二种行为是"by design",无法控制。如果你想避免它,请确保使用全新的 DbContext
实例来执行单个查询以重试所需的数据。
更新: 从 v2.1 开始,EF Core 支持 Lazy Loading. However it's not enabled by default, so in order to utilize it one should mark all navigation properties virtual
, install Microsoft.EntityFrameworkCore.Proxies and enable it via UseLazyLoadingProxies
call, or utilize Lazy-loading without proxies - 两者都在 EF Core 文档中用示例进行了解释。
使用包管理器控制台安装Microsoft.EntityFrameworkCore.Proxies
install-package Microsoft.EntityFrameworkCore.Proxies
然后在您的上下文中 class 添加 .UseLazyLoadingProxies()
:
namespace SomeAPI.EFModels
{
public partial class SomeContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder
.UseLazyLoadingProxies()
.UseSqlServer(connectionString);
}
}
}
}