问题
Here's the scenario:
I have 3 objects called Person, VideoGame, and Store.
One Person can have many VideoGames
One VideoGame can belong to many Persons
Same M:N relationship is between Store and VideoGames
In the DB, the only thing besides these entities are two simple join tables PersonsVideoGames and StoresVideoGames.
Assume everything has an Id property and they are unique.
Business Rules:
- I do not want a video game to be in the VideoGames table if it is not associated with anything (an orphan)
- I do want it in the table if it associated with at least one other object
- You do not manage VideoGames directly, rather the other sides (Store, Person) manage saving/deleting video games.
Is this possible to do using NHibernate mapping? From my actual project implementation, it doesn't seem to work at the basic Person <-> VideoGame level.
NHibernate currently will delete the VideoGame even though it is still associated with other Persons (it is not truly an orphan).
My mapping looks like:
Person Has M:N of VideoGame as a set, with cascade style all-delete-orphan enabled.
VideoGame Has M:N of Person as a set, with lazy-load, inverse, and cascade style save-update enabled.
The Person does not have a public setter for its VideoGames property. It has a function like so:
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
Then whenever I save a Person, I get a list of video games (either existing already or brand new), then use that set method:
' 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)
A video game can be referred to using a more friendly ID like "ShortTitle" as an example. The saving then takes in a IEnumerable(Of String) like "DA:O,BatmanAA,LBP2" etc. and then finds any existing video games in the DB for that Person that match it or creates a new domain object with that short title (assume only Id and ShortTitle are the only properties).
So, does anyone know what's wrong? How come NHibernate isn't detecting that a VideoGame is already associated with other Persons when it removes a VideoGame from that set?
Furthermore, assuming I got this working, will this scenario even work once I set up more M:N relationships (like Stores)?
回答1:
all-delete-orphan
is not that powerful. If you have other relationships, you have to manage delete cascading manually.
来源:https://stackoverflow.com/questions/3621328/problem-with-nhibernate-not-detecting-other-associations-when-all-delete-orphan