シナリオは次のとおりです。
Person、VideoGame、Store という 3 つのオブジェクトがあります。
1 人で複数のビデオゲームを所有できる
1 つのビデオゲームは多くの人に属することができます
Store と VideoGames の間の同じ M:N 関係
DB では、これらのエンティティ以外に、2 つの単純な結合テーブル PersonsVideoGames と StoresVideoGames だけがあります。
すべてに Id プロパティがあり、一意であると仮定します。
ビジネスルール:
- ビデオ ゲームが何にも関連付けられていない場合(孤児) 、ビデオ ゲームを VideoGames テーブルに入れたくありません。
- 少なくとも1つの他のオブジェクトに関連付けられている場合は、テーブルに入れたい
- ビデオゲームを直接管理するのではなく、反対側 (Store、Person) がビデオ ゲームの保存/削除を管理します。
NHibernate マッピングを使用してこれを行うことは可能ですか? 私の実際のプロジェクトの実装から、基本的な人物 <-> ビデオゲーム レベルでは機能しないようです。
NHibernate は現在、VideoGame が他の Person に関連付けられている場合でも、その VideoGame を削除します (これは本当に孤児ではありません)。
私のマッピングは次のようになります。
Person は VideoGame の M:N をセットとして持ち、カスケード スタイルの all-delete-orphan が有効になっています。
VideoGame には M:N の Person がセットとしてあり、遅延ロード、逆、およびカスケード スタイルの保存更新が有効になっています。
Person には、その VideoGames プロパティのパブリック セッターがありません。次のような機能があります。
Public Overridable Sub SetVideoGames(ByVal games As IEnumerable(Of VideoGame))
If Me.VideoGames Is Nothing Then Exit Sub
' Add if the game isn't in the old list.
For Each g In games
If Not Me.VideoGames.Any(Function(g2) g2.Id = g.Id) Then
Me.VideoGames.Add(usr)
End If
Next
' Remove if the game isn't in the new list
For Each g In Me.VideoGames.ToList()
If Not games.Any(Function(g2) g2.Id = g.Id) Then
Me.VideoGames.Remove(g)
End If
Next
End Sub
次に、Person を保存するたびに、ビデオ ゲームのリスト (既存のものまたは新しいもの) を取得し、その set メソッドを使用します。
' listOfVideogames is just a list of ShortTitle strings
Dim result As New List(Of VideoGame)()
Dim newGames As New List(Of VideoGame)()
Dim existingGames As IList(Of VideoGame) ' = Session.Get(blah, gets the existing games for this person)
' Add the existing games to the result set
result.AddRange(existingGames)
' Get any titles from the given list not in the existing list
For Each title In listOfVideogames.Except(existingGames.Select(Function(g) g.ShortTitle))
Dim newGame As New VideoGame() With {
.ShortTitle = title
}
newGames.Add(newGame)
Next
' Add them to the resultset
result.AddRange(newGames)
existingPerson.SetVideoGames(result)
' Do other updates
MyNHibernateDataProvider.Save(existingPerson)
ビデオ ゲームは、例として "ShortTitle" のようなわかりやすい ID を使用して参照できます。保存は、「DA:O,BatmanAA,LBP2」などの IEnumerable(Of String) を取り込み、それに一致するその Personの DB 内の既存のビデオ ゲームを検索するか、その短いタイトルで新しいドメイン オブジェクトを作成します ( Id と ShortTitle のみがプロパティであると仮定します)。
それで、誰かが何が悪いのか知っていますか?NHibernate は、VideoGame をそのセットから削除するときに、VideoGame が既に他の Person に関連付けられていることを検出しないのはなぜですか?
さらに、これが機能すると仮定すると、このシナリオは、さらに M:N の関係 (ストアなど) を設定した後でも機能しますか?