gpt4 book ai didi

c# - EntityFramework 延迟加载在不同的上下文中不起作用

转载 作者:行者123 更新时间:2023-11-30 16:40:34 25 4
gpt4 key购买 nike

我试图了解延迟加载在 Entity Framework 6 中是如何工作的。在我看来,延迟加载只适用于 DbContext,其中“to-be-loaded”属性已经存在访问过。请查看下面的示例 - 测试 LazyLoad_InSameContext 成功,而测试 LazyLoad_InDifferentContext 失败。

这是有意为之的行为吗?两个测试不应该都成功吗?

using System.Transactions;
using NUnit.Framework;
using System.Data.Entity;

namespace EfTestProject
{
[TestFixture]
public class Test
{
[Test]
public void LazyLoad_InDifferentContext()
{
Team team;
Employee employee;
using (var context1 = new Context())
{
team = new Team();
context1.Teams.Add(team);
context1.SaveChanges();
}
using (var context2 = new Context())
{
employee = new Employee {TeamId = team.Id};
context2.Employees.Add(employee);
context2.SaveChanges();

Assert.NotNull(employee.Team); // <- This fails!
}
}

[Test]
public void LazyLoad_InSameContext()
{
Team team;
Employee employee;
using (var context1 = new Context())
{
team = new Team();
context1.Teams.Add(team);
context1.SaveChanges();

employee = new Employee { TeamId = team.Id };
context1.Employees.Add(employee);
context1.SaveChanges();

Assert.NotNull(employee.Team); // <- This works!
}
}
[SetUp]
public void SetUp()
{
new Context().Database.CreateIfNotExists();
}
}

public class Context : DbContext
{
public Context() : base("name=Context") { }
public virtual DbSet<Team> Teams { get; set; }
public virtual DbSet<Employee> Employees { get; set; }
}

public class Team
{
public int Id { get; set; }
}

public class Employee
{
public int Id { get; set; }
public int? TeamId { get; set; }
public virtual Team Team { get; set; }
}
}

编辑1:

可以通过在创建员工之前添加 context2.Teams.Attach(team); 来“修复”测试。我不明白为什么这是必要的。

using (var context2 = new Context())
{
context2.Teams.Attach(team);
employee = new Employee {TeamId = team.Id};
context2.Employees.Add(employee);
context2.SaveChanges();
employee = context2.Employees.Find(employee.Id);

Assert.NotNull(employee.Team);
}

编辑2:

如果我使用 context2.Employes.Create() 创建新实体,它也会成功:

using (var context2 = new Context())
{
employee = context2.Employees.Create();
employee.TeamId = team.Id;
context2.Employees.Add(employee);
context2.SaveChanges();

Assert.NotNull(employee.Team);
}

最佳答案

即使启用延迟加载,EF DbContext 也不会自动从数据库加载任何内容。当您通过添加或附加实体将实体与 DbContext 关联时,DbContext 将通过虚拟导航属性关联它知道的任何引用。

例如:给定父/子关系,其中 1 个父项有多个子项,并且数据库中已有 ParentID 为 10 的 Parent 记录。

using (var context = new TestDbContext())
{
var child = new Child { Name = "test", ParentId = 10 };
context.Children.Add(child);
context.SaveChanges();
Assert.IsNull(child.Parent);
}

父 ID 将设置为 10,但父引用将为空。上下文根本不知道它。如果您稍后加载该父实体,甚至没有将其关联到实体,那么很快,代理将返回它。DbContext 遍历加载的实体以查找可能引用加载的父实体并将其关联的任何内容。 (这样的行为可能是长期存在的 DbContext 变慢的原因。)

using (var context = new TestDbContext())
{
var child = new Child { Name = "test", ParentId = 10 };
context.Children.Add(child);
context.SaveChanges();
Assert.IsNull(child.Parent);
var parent = context.Parents.Find(10);
Assert.IsNotNull(child.Parent); // Poof, Parent is now a proxy pointing to the Parent.
}

在 DbContext 相对长期存在的情况下,这会变得很尴尬,因为它对相关实体的了解可能会有所不同,具体取决于相关代码可能加载或未加载的内容,从而导致间歇性 NullReferenceExceptions 等。

这是避免在具有导航属性的实体中使用 FK 属性的一个很好的理由,而只是将导航属性与在幕后映射的键或阴影属性一起使用。 (EF Core) 使用 FK 和导航属性时,在设置或更改 FK 后从导航引用获取信息时,您需要注意一些可能看起来很奇怪的行为。只处理导航属性通常更安全。

关于c# - EntityFramework 延迟加载在不同的上下文中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51138722/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com