c# EF4.0 POCO -如何设置导航属性与实体从不同的DbContext

本文关键字:实体 属性 导航 DbContext 设置 POCO EF4 何设置 | 更新日期: 2023-09-27 18:03:44

我想在实体上设置一个外键。我有外部实体暴露在我的用户控件,并希望通过WinForms数据绑定设置它。

这里有一个问题——外部实体最初是从另一个存储库/DbContext加载的,因为用户控件使用自己的存储库独立地填充自己。

不幸的是,这并不能"开箱即用"地工作,如下例所示:

var repository1 = GetRepository();
var categoryFromRepository1 = repository1.GetAll<Category>().First();
var repository2 = GetRepository();
var appointmentFromRepository2 = repository2.GetNewAppointment();
appointmentFromRepository2 .Category = categoryFromRepository1;
repository2.Add(appointmentFromRepository2);
repository2.SaveChanges();

在Add()上失败,出现以下错误:

An entity object cannot be referenced by multiple instances of IEntityChangeTracker.

好,所以repository2不能自动附加Category因为它附加到repository1。很好,让我们先分离:

repository1.Detach(categoryFromRepository1);

由于验证错误而在SaveChanges()上失败-哎呀,原来repository2认为它是一个已添加的条目并试图插入。很好,那么我们来附加一下,以避免出现这种情况:

repository2.Attach(categoryFromRepository1);

这是可行的!问题解决了。现在我已经将repository2-entity属性设置为repository1-entity,瞧。

除了这个溶液吸收沼泽水…我们在整个程序中有许多数据绑定的自填充用户控件,在SaveChanges()之前手动分离/重新附加所有外部实体引用是一个可怕的解决方案。此外,假设我们正在保存的存储库碰巧已经附加了对象,那么在Attach()时就会得到这个错误:

An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.

我能想到的解决方案都没有那么好:

1)在SaveChanges()上的通用存储库类中,扫描所有修改实体上的所有外部引用以查找dbcontext外的实体引用,动态地将它们更改为dbcontext内的实体引用(必要时从DB加载)

2)根本不设置导航属性,只设置外键ID字段(sucks0rz yo' b0x0rz)

3)在保存(违反DRY &持久化透明原则)

4)放弃对这些属性的数据绑定,手动设置属性&从主存储库加载实体(糟糕——意味着对我们已经拥有的数据进行额外的查询)

5)蒙骗用户控制,以便他们可以在需要时从给定的存储库加载数据(糟糕的解决方案,违反了一些基本的设计原则……但可行的)

还有其他的想法吗?

问候,

c# EF4.0 POCO -如何设置导航属性与实体从不同的DbContext

给定多个DbContext实例的存在,似乎您有多个有界的上下文在发挥作用。具体来说,有多个聚集体在起作用,即CategoryAppointment。由于您遇到的问题,最好只使用标识值实现聚合之间的引用——而不是直接的对象引用。如果Appointment仅通过ID引用Category,就不会有这个问题。不过,为了显示目的,您可能需要整个Category聚合。这个需求可以通过使用read-model模式来解决。

查看Effective Aggregate Design了解更多信息