Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In nhibernate, not able to update list of child objects

i have x which an object of type objectX which has a property ListOfObjectYs thats a

List<objectY>

the nhibernate mapping looks like this:

    public ObjectXMap()
    {
        HasMany(x => x.ListOfObjectYs).AsBag().Inverse(); 
    }

when i go to save it, i change some properties on objectX and then have:

    Session.SaveOrUpdate(x);

now i need to update this property that is a list. I get a new list of objectYs and i want to replace the existing list of objectY with a new list. do i need to do this?

  foreach (ObjectY y in x.ListOfObjectYs)
                {
                   Session.Delete(y);
                    deleted = true;
                }
                if (deleted)
                {
                   _session.Flush();
                }
                x.ListOfObjectYs.Clear();

                foreach (ObjectY y in newObjectYList)
                {
                    x.ListOfObjectYs.Add(y);
                   Session.SaveOrUpdate(y);
                }
                _session.Flush();

my questions are:

  1. Do i have to delete everything and flush before adding new ones.
  2. Do i need to do all of these incremental saves in between

is there a better way of doing this update where i need to update an object (properties) but also update properties that are list where there is a whole new list (meaning that items need to be deleted and added).

like image 761
leora Avatar asked Dec 10 '10 02:12

leora


2 Answers

The answers to your questions are no and no. If you want to replace the list you should clear it and add new items. If you have cascade set to all-delete-orphan, as in James Kovacs' answer, then the changes to the collection will be persisted when the session is flushed.

It's important to understand what Save, Update, and SaveOrUpdate mean in NHibernate:

  • Save - make a new object persistent
  • Update - make a changed detached object persistent
  • SaveOrUpdate - Save or Update depending on the unsaved-value of the object's identifier

See also Manipulating Persistent Data.

Assuming that all your objects were loaded in the same session then replacing a collection may be as easy as:

x.ListOfObjectYs.Clear();
foreach (ObjectY y in newObjectYList)
{
    x.ListOfObjectYs.Add(y);
}
_session.Flush();
like image 141
Jamie Ide Avatar answered Oct 30 '22 23:10

Jamie Ide


You need a cascade on your HasMany(). If the child objects are fully owned by the parent, Cascade.AllDeleteOrphan() is a good choice. This way saves, updates, and deletes on the parent are automatically cascaded to the child objects, which removes the need for your complex foreach block. With this in place, simply update your collection and commit your transaction. NHibernate will take care of the rest.

UPDATE: To modify the list, simply add and remove items from the list as you normally would with a .NET collection. For example:

public void RemoveY(ObjectY someY) {
    ListOfObjectYs.Remove(someY);
}

public void AddY(ObjectY someY) {
    ListOfObjectYs.Add(someY);
}

public void ClearAllY() {
    ListOfObjectYs.Clear();
}

When the transaction is committed, any changes to the ListOfObjectYs collection will be persisted along with the parent ObjectX.

like image 25
James Kovacs Avatar answered Oct 30 '22 22:10

James Kovacs