EF Core 5.0.4 - 从核心 3.1 升级后,通过 Include() 进行预加载不起作用
EF Core 5.0.4 - Eager Loading via Include() does not work after upgrade from core 3.1
我们最近从 3.1 迁移到 .net core 5.0.4,EF 预先加载已停止运行。它不再加载依赖对象。
我们尝试像这样加载依赖实体(但未加载相关权限对象):
var test = _db.Guardians.Include(x => x.Permissions).First(x => x.Id == id);
虽然填充了PermissionId Fk,但依赖实体不是:
除了迁移到 EF Core 5 之外,没有其他变化。
POCO 以防有帮助:
public class GuardianModel : PersonModel
{
public int PermissionsId { get; set; }
[ForeignKey("PermissionsId")]
public virtual GuardianPermission Permissions { get; set; }
public GuardianModel() : base()
{
Permissions = new GuardianPermission();
Active = true;
}
}
public class GuardianPermission
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public bool MessageAsEmail { get; set; }
public bool Permission { get; set; }
public bool Message { get; set; }
public bool CovidReportEmail { get; set; }
public bool PermissionEmails { get; set; }
public bool System { get; set; }
public GuardianPermission()
{
MessageAsEmail = true;
Permission = true;
Message = true;
PermissionEmails = true;
}
}
我已经尝试了 google 返回的每个答案,添加了明确的 FK 引用,FK 不再可为空,删除了 virtual 关键字,没有任何区别。
非常感谢任何 guidance/troubleshooting 步骤。
根据@apocalypse 的建议,它与中断更改有关 https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-5.0/breaking-changes#nonnullreferences :
非空引用导航不会被查询覆盖
跟踪问题 #2693
旧行为
在 EF Core 3.1 中,急切初始化为非空值的引用导航有时会被数据库中的实体实例覆盖,无论键值是否匹配。但是,在其他情况下,EF Core 3.1 会做相反的事情并保留现有的非空值。
新行为
从 EF Core 5.0 开始,非 null 引用导航永远不会被查询返回的实例覆盖。
请注意,仍然支持将集合导航预先初始化为空集合。
为什么
将引用导航 属性 初始化为“空”实体实例会导致模棱两可的状态。例如:
C#
public class Blog
{
public int Id { get; set; }
public Author Author { get; set; ) = new Author();
}
通常,对博客和作者的查询将首先创建博客实例,然后根据从数据库返回的数据设置适当的作者实例。但是,在这种情况下,每个 Blog.Author 属性 都已初始化为空作者。除了 EF Core 没有办法知道这个实例是“空的”。因此,覆盖此实例可能会悄无声息地丢弃有效的作者。因此,EF Core 5.0 现在始终不会覆盖已初始化的导航。
在大多数情况下,此新行为也与 EF6 的行为一致,尽管经过调查我们也发现了 EF6 中的一些不一致情况。
缓解措施
如果遇到此中断,则解决方法是停止急切地初始化引用导航属性。
就我而言:
public GuardianModel() : base()
{
Permissions = **new GuardianPermission();**
Active = true;
}
违规行在上面以粗体显示。我的解决方案是删除默认初始化并确保从属 class 在主 class 实例化后实例化。有没有更好的办法。即:
var g = new GuardianModel();
g.Permissions = new GuardianPermission();
肯定有比定位上述所有实例更好的方法。
好的,所以我 post 我的评论作为答案:
EF Core 5.0 中的重大更改
“非空引用导航不会被查询覆盖”
https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-5.0/breaking-changes#nonnullreferences
即如果导航 属性 是 not null - 它不会被 EF 填充
(空集合除外)。
来自文档:
旧行为
在 EF Core 3.1 中,急切初始化为非空值的引用导航有时会被数据库中的实体实例覆盖,无论键值是否匹配。但是,在其他情况下,EF Core 3.1 会做相反的事情并保留现有的非空值。
新行为
从 EF Core 5.0 开始,非 null 引用导航永远不会被查询返回的实例覆盖。
请注意,仍然支持将集合导航预先初始化为空集合。
我们最近从 3.1 迁移到 .net core 5.0.4,EF 预先加载已停止运行。它不再加载依赖对象。
我们尝试像这样加载依赖实体(但未加载相关权限对象):
var test = _db.Guardians.Include(x => x.Permissions).First(x => x.Id == id);
虽然填充了PermissionId Fk,但依赖实体不是:
除了迁移到 EF Core 5 之外,没有其他变化。
POCO 以防有帮助:
public class GuardianModel : PersonModel
{
public int PermissionsId { get; set; }
[ForeignKey("PermissionsId")]
public virtual GuardianPermission Permissions { get; set; }
public GuardianModel() : base()
{
Permissions = new GuardianPermission();
Active = true;
}
}
public class GuardianPermission
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public bool MessageAsEmail { get; set; }
public bool Permission { get; set; }
public bool Message { get; set; }
public bool CovidReportEmail { get; set; }
public bool PermissionEmails { get; set; }
public bool System { get; set; }
public GuardianPermission()
{
MessageAsEmail = true;
Permission = true;
Message = true;
PermissionEmails = true;
}
}
我已经尝试了 google 返回的每个答案,添加了明确的 FK 引用,FK 不再可为空,删除了 virtual 关键字,没有任何区别。
非常感谢任何 guidance/troubleshooting 步骤。
根据@apocalypse 的建议,它与中断更改有关 https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-5.0/breaking-changes#nonnullreferences :
非空引用导航不会被查询覆盖 跟踪问题 #2693
旧行为 在 EF Core 3.1 中,急切初始化为非空值的引用导航有时会被数据库中的实体实例覆盖,无论键值是否匹配。但是,在其他情况下,EF Core 3.1 会做相反的事情并保留现有的非空值。
新行为 从 EF Core 5.0 开始,非 null 引用导航永远不会被查询返回的实例覆盖。
请注意,仍然支持将集合导航预先初始化为空集合。
为什么 将引用导航 属性 初始化为“空”实体实例会导致模棱两可的状态。例如:
C#
public class Blog
{
public int Id { get; set; }
public Author Author { get; set; ) = new Author();
}
通常,对博客和作者的查询将首先创建博客实例,然后根据从数据库返回的数据设置适当的作者实例。但是,在这种情况下,每个 Blog.Author 属性 都已初始化为空作者。除了 EF Core 没有办法知道这个实例是“空的”。因此,覆盖此实例可能会悄无声息地丢弃有效的作者。因此,EF Core 5.0 现在始终不会覆盖已初始化的导航。
在大多数情况下,此新行为也与 EF6 的行为一致,尽管经过调查我们也发现了 EF6 中的一些不一致情况。
缓解措施 如果遇到此中断,则解决方法是停止急切地初始化引用导航属性。
就我而言:
public GuardianModel() : base()
{
Permissions = **new GuardianPermission();**
Active = true;
}
违规行在上面以粗体显示。我的解决方案是删除默认初始化并确保从属 class 在主 class 实例化后实例化。有没有更好的办法。即:
var g = new GuardianModel();
g.Permissions = new GuardianPermission();
肯定有比定位上述所有实例更好的方法。
好的,所以我 post 我的评论作为答案:
EF Core 5.0 中的重大更改
“非空引用导航不会被查询覆盖”
https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-5.0/breaking-changes#nonnullreferences
即如果导航 属性 是 not null - 它不会被 EF 填充 (空集合除外)。
来自文档:
旧行为
在 EF Core 3.1 中,急切初始化为非空值的引用导航有时会被数据库中的实体实例覆盖,无论键值是否匹配。但是,在其他情况下,EF Core 3.1 会做相反的事情并保留现有的非空值。
新行为
从 EF Core 5.0 开始,非 null 引用导航永远不会被查询返回的实例覆盖。
请注意,仍然支持将集合导航预先初始化为空集合。