Problem with NHibernate not detecting other associations when all-delete-orphan is set on a M:N relationship

☆樱花仙子☆ 提交于 2019-12-12 01:39:35

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!