3

WidgetCollection というクラスがあります。List(Of Widget) と SelectedWidget プロパティを公開する Items プロパティがあります。私は、EF が次のようにデータベースを構築することを期待しています。

  • Widgets テーブルに WidgetCollection_Id プロパティを追加し、各ウィジェットがどの WidgetCollection にあるかを指定します
  • WidgetCollection テーブルに SelectedWidget_Id プロパティを追加し、どのウィジェットを選択するかを指定します
  • WidgetCollection.Id から Widget.WidgetCollection_Id に 1 対多の関係を追加します。
  • Widget.Id から WidgetCollection.SelectedWidget_Id に 1 対 0 または 1 の関係を追加します。

データベース スキーマが正しく構築されているように見えることは確認できますが、SelectedWidget に割り当てた後にコンテキストを保存すると、次のエラーが発生します。

System.Data.Entity.Infrastructure.DbUpdateException が発生しました HResult=-2146233087 Message=関係の外部キー > プロパティを公開しないエンティティの保存中にエラーが発生しました。単一のエンティティを例外のソースとして識別できないため、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
4

1 に答える 1

2

例外は、それが言うことを意味すると思います:

依存操作の有効な順序を判別できません。

この二行…

oWidgetCollection.Widgets.Add(oWidgetA)
oWidgetCollection.SelectedWidget = oWidgetA 

...つまり、EF はに外部キーをoWidgetCollection設定する前にを格納する必要がありますが、2 行目ではオブジェクトを逆に格納する必要があります。つまり、EF が に外部キーを設定する前に格納する必要があります。WidgetCollection_IdoWidgetAoWidgetASelectedWidget_IdoWidgetCollection

競合を解決するには、変更を 2 回保存する必要があると思います。

oWidgetCollection.Widgets.Add(oWidgetA)
oWidgetCollection.Widgets.Add(oWidgetB)

oContext.WidgetCollections.Add(oWidgetCollection)
oContext.SaveChanges()

oWidgetCollection.SelectedWidget = oWidgetA
oContext.SaveChanges()

ちなみに、この予想…

Widget.Id から WidgetCollection.SelectedWidget_Id に 1 対 0 または 1 の関係を追加します。

...正しくありません。EF は別の 1 対多の関係を作成します。つまり、同じ関係SelectedWidgetを多数の に対して選択できますWidgetCollection。リレーションシップの一方の側にのみナビゲーション プロパティがある場合、慣例により EF が作成する既定のリレーションシップは、常に 1 対多です。このデフォルトの動作をオーバーライドするには、データ注釈または Fluent API が必要です。

この関係は 1 対多のままにしておくことをお勧めします。1 対 1 のリレーションシップはより難しく、EF は共有プライマリ キーを使用した 1 対 1 のリレーションシップのみをサポートします。これは、選択したとおりに異なるウィジェットを選択できないことを意味します。選択できる唯一のウィジェットは、WidgetCollection と同じ主キー値を持つウィジェットです。

于 2012-10-25T20:00:25.523 に答える