我有一个名为WidgetCollection的类。它有一个Items属性,公开List(Of Widget)和SelectedWidget属性。我希望EF能够按如下方式构建数据库:
我可以确认它看起来确实正确构建了数据库模式,但如果我在分配给SelectedWidget后保存了上下文,则会出现以下错误:
发生了System.Data.Entity.Infrastructure.DbUpdateException 的HResult = -2146233087 消息=保存未公开外键的实体时发生错误>他们关系的属性。 EntityEntries属性将返回null,因为无法将单个实体标识为异常源。通过在实体类型中公开外键属性,可以更轻松地在保存时处理异常。
内部例外
无法确定相关操作的有效排序。由于外键约束,模型要求或存储生成的值,可能存在依赖关系。
我可以通过永不分配WidgetCollect.SelectedWidget来阻止此错误。
我想问题是EF无法弄清楚如何处理两个方向的关系,但我找不到一种方法将它指向正确的方向。示例代码如下,欢迎所有建议!
Public Class Widget
Private miId As Integer
Public Property Id As Integer
Get
Return miId
End Get
Set(value As Integer)
miId = value
End Set
End Property
Private msName As String
Public Property Name As String
Get
Return msName
End Get
Set(value As String)
msName = value
End Set
End Property
End Class
Public Class WidgetCollection
Private miId As Integer
Public Property Id As Integer
Get
Return miId
End Get
Set(value As Integer)
miId = value
End Set
End Property
Private msName As String
Public Property Name As String
Get
Return msName
End Get
Set(value As String)
msName = value
End Set
End Property
Private moSelectedWidget
Public Property SelectedWidget As Widget
Get
Return moSelectedWidget
End Get
Set(value As Widget)
moSelectedWidget = value
End Set
End Property
Private moWidgets As New List(Of Widget)
Public Property Widgets As List(Of Widget)
Get
Return moWidgets
End Get
Set(value As List(Of Widget))
moWidgets = value
End Set
End Property
End Class
Public Class MyContext
Inherits DbContext
Public Property Widgets As DbSet(Of Widget)
Public Property WidgetCollections As DbSet(Of WidgetCollection)
End Class
Class Application
Public Sub New()
Database.DefaultConnectionFactory = New SqlCeConnectionFactory("System.Data.SqlServerCe.4.0", "", "Data Source=\EFtest.sdf")
Database.SetInitializer(New DropCreateDatabaseIfModelChanges(Of MyContext))
Dim oContext = New MyContext
Dim oWidgetA = New Widget With {.Name = "Widget A"}
Dim oWidgetB = New Widget With {.Name = "Widget A"}
Dim oWidgetCollection = New WidgetCollection With {.Name = "My widget collection"}
oWidgetCollection.Widgets.Add(oWidgetA)
oWidgetCollection.Widgets.Add(oWidgetB)
oWidgetCollection.SelectedWidget = oWidgetA 'Removing this line prevents error
oContext.WidgetCollections.Add(oWidgetCollection)
oContext.SaveChanges()
End Sub
End Class
答案 0 :(得分:2)
我认为异常意味着它所说的内容:
无法确定相关操作的有效排序。
这两行...
oWidgetCollection.Widgets.Add(oWidgetA)
oWidgetCollection.SelectedWidget = oWidgetA
...意味着EF必须先存储oWidgetCollection
才能在WidgetCollection_Id
中设置oWidgetA
外键,但第二行需要以相反的方式存储对象,即,在EF可以在oWidgetA
中设置外键SelectedWidget_Id
之前必须存储oWidgetCollection
。
要解决冲突,我认为您必须将更改保存两次:
oWidgetCollection.Widgets.Add(oWidgetA)
oWidgetCollection.Widgets.Add(oWidgetB)
oContext.WidgetCollections.Add(oWidgetCollection)
oContext.SaveChanges()
oWidgetCollection.SelectedWidget = oWidgetA
oContext.SaveChanges()
顺便说一句:这个期望......
从Widget.Id添加1对0或1关系到WidgetCollection.SelectedWidget_Id
......不正确。 EF将创建另一个一对多关系,即可以为许多SelectedWidget
选择相同的WidgetCollection
。当您仅在关系的一侧具有导航属性时,默认关系EF将按惯例创建,始终为一对多。您需要数据注释或Fluent API来覆盖此默认行为。
我建议将这种关系保持为一对多。一对一关系更加困难,EF仅支持与共享主键的一对一关系,这意味着您无法选择不同的小部件。唯一可能选择的小部件将是具有与WidgetCollection相同的主键值的小部件。