我正在尝试Entity Framework 4.0,这里是 案例的最简化版本 -
我有以下两个相关表格 -
地址
标识
城市
客户端
标识
AddressId
姓名
我已经在ComboBox中加载了地址。我想要的只是在TextBox中输入客户端名称,从ComboBox中选择一个地址作为客户端的地址并点击保存按钮。我希望我的客户端保存在Client表中。这是我试过的 -
/*loads Addresses to the ComboBox*/
private void LoadData()
{
using (CAEntities ctx = ModelAccess.GetContext())
this.AddressList = ctx.Addresses.ToList();
}
/*(tries) to insert the Client to the database*/
private void Save()
{
/*here this.Client is the Client object that is instantiated & initialized
by previous code and this.Address is the SelectedItem of the ComboBox*/
this.Client.Address = this.Address;
using (CAEntities ctx = ModelAccess.GetContext())
{
ctx.Clients.AddObject(this.Client);
ctx.SaveChanges();
}
}
朱莉勒曼在Programming Entity Framework表示,...Because the
entities are joined, you can add either entity, and it will bring along the rest of the graph...
但是我有是一个InvalidOperationException,说“当该属性的当前值是空的的EntityKey属性只能设置。” <无线电通信/>
如果我使用 -
this.Client.AddressId = this.Address.Id;
而不是 -
this.Client.Address = this.Address;
客户端完美地插入数据库。但我认为我也应该能够直接将实体联系起来,对吧? 我假设问题与我正在创建的单独上下文有关。所以我尝试了这个 -
private void Save()
{
this.Client.Address = this.Address;
using (CAEntities ctx = ModelAccess.GetContext())
{
ctx.Addresses.Attach(this.Address);
ctx.SaveChanges();
}
}
但是这次我得到一个InvalidOperationException,它说“具有临时EntityKey值的对象不能附加到对象上下文”。那么我在这里做错了什么呢?提前谢谢。
答案 0 :(得分:2)
这应解决问题:
using (CAEntities ctx = ModelAccess.GetContext())
{
ctx.Addresses.Attach(this.Address);
this.Client.Address = this.Address;
ctx.Clients.AddObject(this.Client);
ctx.SaveChanges();
}
为什么这样做?
DbContext会跟踪它被拉下或已明确附加到它的对象。在您的情况下,您将this.Client.Address
设置为DbContext不知道的对象。在某些情况下,这将导致实体框架插入一个新的客户端行和一个新的地址行,但在您的情况下,由于某些语义细节,我不知道,它提出了一个模糊的异常。
通过将this.Address
附加到DbContext,实体框架了解地址已存在于数据库中,并且您在将其分配给this.Client.Address
时正在创建与现有对象的关联。
IMO,实体框架的语义需要更好地记录。有很多这样的案例会引发误导或模糊的异常。例如,在附加对象时,请务必记住它们是递归附加的。如果您要在新数据上下文中附加this.Client
,它也会以递归方式附加this.Client.Address
,并且任何其他实体this.Client
都可以引用。出于这个原因,如果您要明确附加this.Client
然后this.Address
,那么您会收到一个例外,因为当您附加this.Client
时,地址已被隐式附加。