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)蒙骗用户控制,以便他们可以在需要时从给定的存储库加载数据(糟糕的解决方案,违反了一些基本的设计原则……但可行的)
还有其他的想法吗?问候,
丹
给定多个DbContext
实例的存在,似乎您有多个有界的上下文在发挥作用。具体来说,有多个聚集体在起作用,即Category
和Appointment
。由于您遇到的问题,最好只使用标识值实现聚合之间的引用——而不是直接的对象引用。如果Appointment
仅通过ID引用Category
,就不会有这个问题。不过,为了显示目的,您可能需要整个Category聚合。这个需求可以通过使用read-model模式来解决。
查看Effective Aggregate Design了解更多信息