Wpf EF4.0-将相关对象插入数据库
我正在尝试实体框架4.0,这里是该案例的最简化版本- 我有以下两个相关表格- 地址Wpf EF4.0-将相关对象插入数据库,wpf,entity-framework,entity-framework-4,entity-relationship,Wpf,Entity Framework,Entity Framework 4,Entity Relationship,我正在尝试实体框架4.0,这里是该案例的最简化版本- 我有以下两个相关表格- 地址 Id 城市 客户端 Id 地址ID 名字 我已将地址加载到组合框中。我只想在文本框中输入客户机名称,从组合框中选择一个地址作为客户机地址,然后点击保存按钮。我希望我的客户机保存在客户机表中。这是我试过的- /*loads Addresses to the ComboBox*/ private void LoadData() { using (CAEntities ctx =
Id
城市 客户端
Id
地址ID
名字 我已将地址加载到组合框中。我只想在文本框中输入客户机名称,从组合框中选择一个地址作为客户机地址,然后点击保存按钮。我希望我的客户机保存在客户机表中。这是我试过的-
/*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();
}
}
Julie Lerman在中说,…因为
实体被连接,您可以添加任何一个实体,它将带来图形的其余部分…
但我遇到的是一个InvalidOperationException,它说“只有当属性的当前值为null时,才能设置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值的对象不能附加到对象上下文。”那么我在这里做错了什么呢?提前感谢。这应该可以解决问题:
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不知道的对象。在某些情况下,这将导致entity framework同时插入一个新的客户端行和一个新的地址行,但在您的情况下,由于一些我不了解的语义细节,它抛出了一个模糊的异常
通过将this.Address
附加到DbContext,entity framework可以理解该地址已经存在于数据库中,并且在将其分配给this.Client.Address
时,您正在创建与现有对象的关联
在我看来,实体框架的语义需要更好地文档化。在很多类似的情况下,会抛出一个误导性的或模糊的异常。例如,在附加对象时,重要的是要记住它们是递归附加的。如果要在新的数据上下文中附加
this.Client
,它也会递归地附加this.Client.Address
,任何其他实体this.Client
都可能引用。因此,如果要显式附加this.Client
然后再附加this.Address
,则会出现异常,因为在附加this.Client
时,该地址已隐式附加,因为您使用this.Client.Address获取的是组合框中的值,而不是Address对象。它正试图在数据库中创建一个新的地址对象,在创建之前,您无法将其分配给客户端。这就是为什么this.Client.AddressId可以工作的原因。您必须用var address=GetById之类的东西来实例化地址(this.Client.AddressId,然后设置Client.Address=Address。@布赖恩:我知道你的建议是有效的,但我不明白我从组合框中获取的是一个值,而不是一个地址对象。我设置了一个地址对象列表作为它的数据源,并且我将当前的SelectedItem
作为这个.Address,然后我获取Id&Cit。)y属性。因为它是数据源。组合框保存的是键值对而不是对象。因此,通过将该键值对作为地址对象分配回客户端,您告诉db上下文在db中创建一个新地址,但它必须存在才能保存到客户端。这就是临时实体密钥消息的位置ng from@Brian:我真的没有理解你。我从xaml中设置组合框的SelectedItem
属性绑定到我的ViewModel中的那个地址。所以每当SelectedItem
更改时,我不应该得到地址对象吗?SelectedItem
,正如这里提到的,返回一个System.object
,你可以强制转换它对于您的自定义对象,我是对的吗?在某种程度上,您是对的,但请记住组合框是什么,它将返回什么,以及您使用它的介质(查看页面)。它只是要从组合框中传回一个键值对。这就是您必须使用的。非常感谢brian,它确实解决了问题:D但您能否详细说明一下,在附加地址之前,我设置this.Client.Address=this.Address;
时到底出了什么问题。我知道ObjectServices
会跟踪只有EntityObject
s是它知道的。在我的例子中,只有Address对象。而且由于客户端对象是在代码中创建的,所以上下文不知道它。但是当我分配this.Client.Address=this.Address;
时,我不是在创建一个完整的对象图,将实体彼此关联起来吗?然后当我附加了地址对象,上下文是否也应该知道客户端对象,因为它现在与地址对象相关?所以我仍然没有得到…临时EntityKey值…
异常。无论如何,再次感谢你。我完全同意你的更好的文档
观点。我看到很多人使用EF但是他们中很少有人知道幕后发生了什么。如果您想查看DbContext如何“查看”实体,请将该实体传递给dataContext.Entry()
方法并检查其EntityState。如果它是分离的,则DbContext不知道它,即使它最初是由以前的DbContext下拉的。必须通过附加对象告诉DbContext,“嘿,这个对象已经存在于数据库中。”这样在保存更改时,DbContext