EF Core 返回空关系,直到直接访问
Posted
技术标签:
【中文标题】EF Core 返回空关系,直到直接访问【英文标题】:EF Core returns null relations until direct access 【发布时间】:2021-12-25 08:25:15 【问题描述】:我有一些类似下面的模型:
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
s,如下所示:
那么突变体的OriginalCode
字段将不为空:
这是什么原因,我该如何解决?
【问题讨论】:
【参考方案1】:EF Core 文档的Loading Related Data 部分解释了原因。
第一个行为是因为 EF Core 当前不支持延迟加载,因此通常您将获得导航属性的 null
,直到您通过急切或显式加载专门加载它们。但是,Eager loading 部分包含以下内容:
提示 Entity Framework Core 将自动修复先前加载到上下文实例中的任何其他实体的导航属性。因此,即使您没有明确包含导航属性的数据,如果之前加载了部分或所有相关实体,该属性仍可能会被填充。
这解释了为什么导航属性在第二种情况下不为空。
现在,我不确定您要修复这两种行为中的哪一种,因此将尝试同时解决这两个问题。
第一个行为可以通过使用当前可用的加载相关数据的方法之一来“修复”,例如急切加载:
var mutants = db.Mutants.Include(m => m.OriginalCode).ToList();
第二种行为是“设计使然”,无法控制。如果您想避免这种情况,请确保使用全新的 DbContext
实例来执行单个查询以重试所需的数据。
更新:从 v2.1 开始,EF Core 支持Lazy Loading。但是默认情况下它没有启用,因此为了使用它,应该标记所有导航属性virtual
,安装Microsoft.EntityFrameworkCore.Proxies 并通过UseLazyLoadingProxies
调用启用它,或使用Lazy-loading without proxies - 两者都在EF Core中的示例中进行了解释文档。
【讨论】:
你可能猜到我想控制第一个行为。但是还有一个很大的问题。你提到的这种方式,我应该明确地解决要填充的关系,对吗? 确实如此。您必须使用多个Include
/ ThenInclude
方法指定要“包含”的每一个。 AFAIK 有一些计划在未来自动实现,但目前这是唯一的选择。
猜猜怎么样,一个人永远不会知道 - 例如在 EF Core 标签中看到你之前的几个问题 - Can I stop Entity Framework Core from populating my result with partial data? :)
现在 EF Core 支持延迟加载:docs.microsoft.com/en-us/ef/core/querying/…
虽然我认为没有设置为默认值,但这意味着它不是推荐的解决方案!我认为如果使用得当,非惰性方法更难编写,但更适合运行时,这将使许多未来的数据库请求合二为一。【参考方案2】:
使用包管理器控制台安装 Microsoft.EntityFrameworkCore.Proxies
install-package Microsoft.EntityFrameworkCore.Proxies
然后在你的 Context 类中添加.UseLazyLoadingProxies()
:
namespace SomeAPI.EFModels
public partial class SomeContext : DbContext
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
if (!optionsBuilder.IsConfigured)
optionsBuilder
.UseLazyLoadingProxies()
.UseSqlServer(connectionString);
【讨论】:
以上是关于EF Core 返回空关系,直到直接访问的主要内容,如果未能解决你的问题,请参考以下文章