Entity framework 实体框架4.1:保存多对多关系将在数据库中再次保存现有子实体
我有一个非常令人沮丧的问题(无论如何对我来说): 我有一个简单的场景,其中我有一个产品实体和一个组合产品实体。它们之间存在多对多关系,因此一个产品可以属于多个组合产品,而一个组合产品可以包含多个产品 我首先创建一个产品并将其保存到数据库中。稍后,我创建一个组合产品并添加此产品。当我试图保存这个组合产品时,产品实体将通过实体框架再次添加到数据库中,而不仅仅是添加关系。。。这真让我发疯 在保存之前,我已经尝试将产品再次附加到上下文,但实体抱怨它已经有一个具有相同密钥的产品 下面是所有这些的代码(简化和代码剥离): 产品实体Entity framework 实体框架4.1:保存多对多关系将在数据库中再次保存现有子实体,entity-framework,entity-framework-4.1,Entity Framework,Entity Framework 4.1,我有一个非常令人沮丧的问题(无论如何对我来说): 我有一个简单的场景,其中我有一个产品实体和一个组合产品实体。它们之间存在多对多关系,因此一个产品可以属于多个组合产品,而一个组合产品可以包含多个产品 我首先创建一个产品并将其保存到数据库中。稍后,我创建一个组合产品并添加此产品。当我试图保存这个组合产品时,产品实体将通过实体框架再次添加到数据库中,而不仅仅是添加关系。。。这真让我发疯 在保存之前,我已经尝试将产品再次附加到上下文,但实体抱怨它已经有一个具有相同密钥的产品 下面是所有这些的代码(简化
Public Class SingleProduct
Property SingleProductId As Integer
Property CombinedProducts As ICollection(Of CombinedProduct)
End Class
组合产品
Public Class CombinedProduct
Public Sub New()
Me.Products = New HashSet(Of SingleProduct)()
End Sub
Property CombinedProductId As Integer
Property Products As ICollection(Of SingleProduct)
End Class
多对多关系定义
Protected Overrides Sub OnModelCreating(modelBuilder As DbModelBuilder)
modelBuilder.Entity(Of CombinedProduct)().
HasMany(Function(c) c.Products).
WithMany(Function(p) p.CombinedProducts).
Map(Sub(m)
m.ToTable("CombinedProductSingleProducts")
m.MapLeftKey("SingleProductId")
m.MapRightKey("CombinedProductId")
End Sub)
End Sub
用于保存的代码
Using myDataContext As New DataContext
myDataContext.CombinedProducts.Add(product)
myDataContext.SaveChanges()
End Using
在保存之前已尝试附加,但无效
For Each prd In product.Products
If myDataContext.Entry(prd).State = EntityState.Detached Then
myDataContext.SingleProducts.Attach(prd)
End If
Next
我找到的一个“解决方案”是在保存之前,清除产品列表,再次从数据库中获取产品,并将其添加到CombinedProduct中,但这很难是解决方案
希望有人能帮我,这让我快发疯了!
(我使用实体框架4.1,首先使用代码)
编辑
Public Class CombinedProduct
Public Sub New()
Me.Products = New HashSet(Of SingleProduct)()
End Sub
Property CombinedProductId As Integer
Property Products As ICollection(Of SingleProduct)
End Class
添加产品:这是在它自己的数据上下文中以其他形式完成的:
Using myDataContext As New DataContext
myDataContext.SingleProducts.Add(singleProduct)
myDataContext.SaveChanges()
End Using
组合产品创建:
Dim myCombinedProduct = New CombinedProduct
myCombinedProduct.Products.Add(product)
我添加的产品首先在其自己的datacontext中再次获取:
Using myDataContext As New DataContext
Return myDataContext.Products.FirstOrDefault(Function(p) p.ProductId = id)
End Using
编辑
Public Class CombinedProduct
Public Sub New()
Me.Products = New HashSet(Of SingleProduct)()
End Sub
Property CombinedProductId As Integer
Property Products As ICollection(Of SingleProduct)
End Class
完整的故事,希望更清楚:
我有一个winforms应用程序,它有两个表单:一个用于管理产品,另一个用于管理组合产品。应用程序是N层(用户层、业务层和数据层)
在管理产品的表单上,您可以简单地添加/更新/删除产品。在这种形式下,一切正常
组合产品形式是另一个问题:
希望这能让事情变得更清楚。在EF中,您试图关联的所有实体都必须属于同一个datacontext,否则它不会将您的产品识别为现有产品,而是会添加一个新的 在首次使用时,必须首先从db获取产品 我从不需要附加/分离实体,但我见过大多数人在这样做时遇到问题 此外,在多对多中,两个实体都必须添加到上下文中,关系只会填充联接表
从讨论中可以看出,对于每种实体类型,您都有一个存储库,并且通过这些存储库方法获取对象。如果是这样的话,那么这个设计就有问题了,因为对象关系存储在一个公共上下文中。您可能认为访问数据库会有一些性能问题,但即使在连接数据库时,您也会访问数据库。我不太清楚您执行哪些步骤的顺序,但正确的顺序应该是: 如果所有事情都发生在一个上下文中:
Using myDataContext As New DataContext
Dim product = myDataContext.Products.FirstOrDefault(Function(p) p.ProductId = id)
Dim myCombinedProduct = New CombinedProduct
myCombinedProduct.Products.Add(product)
myDataContext.CombinedProducts.Add(myCombinedProduct)
End Using
加载产品
会附加到上下文并避免重复。必须在将myCombinedProduct
添加到上下文之前执行此操作
如果在另一个上下文中加载产品
:
Using myDataContext As New DataContext
myDataContext.Products.Attach(product)
Dim myCombinedProduct = New CombinedProduct
myCombinedProduct.Products.Add(product)
myDataContext.CombinedProducts.Add(myCombinedProduct)
End Using
在将myCombinedProduct
添加到上下文之前,您必须将product
附加到新上下文
编辑
Public Class CombinedProduct
Public Sub New()
Me.Products = New HashSet(Of SingleProduct)()
End Sub
Property CombinedProductId As Integer
Property Products As ICollection(Of SingleProduct)
End Class
如果您的新myCombinedProduct
包括产品集合以分离状态进入数据层,则以下操作应有效:
Using myDataContext As New DataContext
For Each prd In myCombinedProduct.Products
myDataContext.SingleProducts.Attach(prd)
Next
myDataContext.CombinedProducts.Add(myCombinedProduct)
End Using
我害怕这样的事情。如何在winforms应用程序中仅使用一个Datacontext?我是否应该在应用程序启动时创建一个datacontext并继续使用它,或者这是一个坏主意?不建议使用长时间运行的datacontext。一种选择是再次将产品放入dataContext(您已经拥有产品的密钥)并限制dataContext的作用域,比如,每当您想联系db时,只需打开一个上下文,获取所需的产品,修改其值,保存并处置dbcontext。但这对我来说真的很奇怪吗?我必须首先从数据库中再次获取产品,当上下文已经知道它们时(我想无论如何,因为当我尝试附加它们时,EF说它不能附加它们,因为具有相同密钥的产品已经在上下文中),但我想这意味着在Winform生命周期的整个时间内都在DataContext上,对吗?我一直在尝试寻找一些文档或博客,如果这是一个可接受的解决方案,或者会有什么后果,但到目前为止没有运气…就像每个人一样,这取决于情况,我会保持简短,我