我尝试搜索SO,但是我发现的所有结果似乎都涉及更新已经保存到数据库的实体的PK。我的情况不同。多个链接的1-1关系不按预期同步PK
我有一个数据库中有1-0..1个关系的3个表。的关系是这样的:
A <- B <- C
其中“< - ”代表的关系,并指出主要的结束。即每个B总是有一个相关的A,但一个A可以没有B.换句话说,A的基数是1,B的是0..1。
每个关系都由从子实体的PK到父实体的PK的FK表示。每个PK是具有客户端生成值的uniqueidentifier
Id
列。我已经从数据库中生成了一个EF 4模型,它与相同的基数具有相同的关系。
我试图将子实体B
和C
添加到现有的A
实体。由于设计原因,这两个新实例是在代码的和平下创建的,并且A
实体与另一个实体中的B
实体链接。此外,我不希望后者知道存在C
。
这里的B
和C
创建代码的样子:
public B CreateB()
{
return new B
{
Id = Guid.NewGuid(),
C = new C(),
};
}
而现在的链接并保存代码:
// a is an instance of A that has been loaded from DB
// and hence has a persistent Id value.
// b is a just-created instance of B
// that has a non-persistent Id value and null reference to A.
void SaveBlahBlahBlah(A a, B b)
{
// At this point b and c have the same Id value.
// It differs from a's Id, but that's expected, they haven't been linked yet.
b.A = a;
// At this point b receives a's Id value, but c keeps the original one,
// therefore the existing b-c link gets broken!
using(var ctx = new MyContext())
{
ctx.As.Attach(a); // This throws exception saying
// I've violated referential integrity.
// It doesn't say which relationship is broken,
// but I guess it's the B-C one since
// the debugger shows them to have different values if PKs
ctx.Bs.AddObject(b);
ctx.SaveChanges();
}
}
我已经试过这既与默认EF的代码生成器(使用EF的Entity
类作为生成实体的基类)以及自跟踪实体代码生成器。结果是一样的。
因此,代码崩溃。原因很可能是A
和B
已链接后,B
和C
获得不同的PK值,这对于具有1-1关系的实体是非法的。
我期望的是C自动将它的PK同步到从A
实例获得的值B
。这似乎是合理的,因为我使用对象图,我有一个现有的B
- C
关系,这是可以的,并且我希望链接B
和A
之后它仍然保持正常。为什么会突破?如果B
或C
存在于数据库中并且我无法更改它们的PK,我会理解它。但情况并非如此,两个实体都是刚创建的。
因为EF要求1-1关系的双方都是PK,所以我不能通过使用与FK的PK列分开来打破密钥链。
我不想手动同步密钥,因为事实上有更多的1-1相关的表,这将需要同步代码出现在很多地方。
我相信我将能够更新STE生成器的T4模板,以将PK更新降级到1-1关系。但我对T4不太熟悉,不太乐意这样做。
我有2个问题:
- 是我在我的情况下级联PK更新的预期错了因为某些原因? (虽然看起来很奇怪)也就是说,它是一个错误还是一个特征?
- 除修改STE模板之外是否还有其他解决问题的方法?也许在EF映射或上下文中有一些神奇的选项?
在此先感谢。
+1解释得很清楚! – 2012-03-27 19:36:24
谢谢。我应该注意到我使用了'Attach',因为没有它,EF试图插入'A',由于'A'已经存在于数据库中,导致错误。从那时起,我改变了模型和风格(当时我使用了EFCF)。所以也许你的建议会奏效,我会试试看。 – 2012-03-28 01:45:18
您可以使用'Attach',但您需要在*与B建立关系之前进行此操作。* – 2012-03-28 02:25:55