Entity framework 多重链接的1-1关系不';按预期同步PKs
我尝试搜索SO,但我找到的所有结果似乎都涉及更新已持久化到DB的实体的PK。我的情况不同 我在一个数据库中有3个表,具有1-0..1关系。这些关系如下所示:Entity framework 多重链接的1-1关系不';按预期同步PKs,entity-framework,entity-framework-4,primary-key,foreign-key-relationship,cascade,Entity Framework,Entity Framework 4,Primary Key,Foreign Key Relationship,Cascade,我尝试搜索SO,但我找到的所有结果似乎都涉及更新已持久化到DB的实体的PK。我的情况不同 我在一个数据库中有3个表,具有1-0..1关系。这些关系如下所示: A <- B <- 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 h
A <- B <- 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的实体
类作为生成实体的基类)和自跟踪实体代码生成器尝试了这两种方法。结果是一样的
所以,代码崩溃了。原因可能是在链接了A
和B
之后,B
和C
获得不同的PK值,这对于具有1-1关系的实体是非法的
我所期望的是C自动将其PK同步到从A
实例获得的B
值。这似乎是合理的,因为我使用的是一个对象图,我有一个现有的B
-C
关系,它是正常的,我希望它在链接B
和A
后保持正常。为什么会破裂?如果数据库中存在B
或C
,并且我无法更改他们的PKs,我会理解的。但事实并非如此,两个实体都是刚刚创建的
我无法通过为FKs使用独立于PKs列来断开键链,因为EF要求1-1关系的两侧都是PKs
我不想手动同步键,因为实际上有更多1-1相关的表,这需要同步代码出现在许多地方
我相信我将能够更新STE生成器的T4模板,以级联PK更新1-1关系。但我对T4不太熟悉,也不太乐意这么做
我有两个问题:
提前感谢。问题在于,处理从一个引用对象到另一个引用对象的ID分配的服务是上下文。但当您实际进行关联时,两个对象都不在上下文中。这通常不会是一个问题,因为当您将B添加到上下文中时,关系将得到修复 不幸的是,你没有这样做。相反,您创建了一个与的附加关系,但随后对上下文撒谎并声称一切都已修复。更准确地说,您可以调用
EntitySet.Attach
,它实际上只用于已经固定的对象
另一方面,这样的代码应该可以正常工作:
public B CreateB()
{
return new B
{
Id = Guid.NewGuid(),
C = new C(),
};
}
void SaveBlahBlahBlah(A a, B b)
{
using(var ctx = new MyContext())
{
ctx.Bs.AddObject(b);
ctx.SaveChanges();
}
}
注意,我在这里所做的只是删除有问题的代码,这与B和C之间的关系无关
简言之,注意附加。你需要知道你打电话时在做什么
更新
处理A
的现有实例的版本:
void SaveBlahBlahBlah(A a, B b)
{
Debug.Assert(a.B != b);
using(var ctx = new MyContext())
{
ctx.As.Attach(a);
a.B = b; // it's crucial that this link is set after attaching a to context!
ctx.Bs.AddObject(b);
ctx.SaveChanges();
}
}
问题在于,处理从一个引用对象到另一个引用对象的ID分配的服务是上下文。但当您实际进行关联时,两个对象都不在上下文中。这通常不会是一个问题,因为当您将B添加到上下文中时,关系将得到修复
不幸的是,你没有这样做。相反,您创建了一个与的附加关系,但随后对上下文撒谎并声称一切都已修复。更准确地说,您可以调用EntitySet.Attach
,它实际上只用于已经固定的对象
另一方面,这样的代码应该可以正常工作:
public B CreateB()
{
return new B
{
Id = Guid.NewGuid(),
C = new C(),
};
}
void SaveBlahBlahBlah(A a, B b)
{
using(var ctx = new MyContext())
{
ctx.Bs.AddObject(b);
ctx.SaveChanges();
}
}
注意,我在这里所做的只是删除有问题的代码,这与B和C之间的关系无关
简言之,注意附加。你需要知道你打电话时在做什么
更新
处理A
的现有实例的版本:
void SaveBlahBlahBlah(A a, B b)
{
Debug.Assert(a.B != b);
using(var ctx = new MyContext())
{
ctx.As.Attach(a);
a.B = b; // it's crucial that this link is set after attaching a to context!
ctx.Bs.AddObject(b);
ctx.SaveChanges();
}
}
谢谢我应该注意,我使用了Attach
,因为没有它,EF试图插入A
,这导致了一个错误,因为A
已经存在于数据库中。从那时起,我改变了模式和口味(我当时使用的是EFCF)。因此,也许你的建议会奏效,我会尝试一下。你可以使用附件
,但在你与B建立关系之前,你需要这样做。好的,它奏效了。我已经编辑了你的答案,以包含我需要的确切代码。然而,我还是不太了解情况。对于依赖于上下文和类来跟踪更改和状态的普通EF来说,这似乎还可以。但是为什么它对STE不起作用呢?他们应该在没有现有背景的情况下跟踪变化,这正是自我跟踪背后的理念,不是吗?谢谢。我应该注意,我使用了Attach
,因为没有它,EF试图插入A
,这导致了一个错误,因为A
已经存在于数据库中。从那时起,我改变了模式和口味(我当时使用的是EFCF)。因此,也许你的建议会奏效,我会尝试一下。你可以使用附件
,但在你与B建立关系之前,你需要这样做。好的,它奏效了。我已经编辑了你的答案,以包含我需要的确切代码。然而,我还是不太了解情况。对于依赖于上下文和类来跟踪更改和状态的普通EF来说,这似乎还可以。但是为什么它对STE不起作用呢?他们应该在没有现有背景的情况下跟踪变化,这正是自我跟踪背后的理念,不是吗?