Cascade save-update in NHibernate mapping means saving parent will automatically save child. So instead of calling Session.SaveOrUpdate(personEmail), calling Session.SaveOrUpdate(person) will cover any email change in email list belongs to same person, given cascade save-update is defined at person model mapping level.
Cascade has a few options to choose from.
The interesting point is, cascade save-update will bump up the version column at both parent and child level. If Person and Email both have a version column defined in table and entity, cascade saving will change both of them.
This will shock many new NHibernate developers. Their reactions are, what if person has many telephones, many addresses, etc, changing any child will touch version column at person table, this will cause more conflict ions in the real world.
Before answers this question, lets pick another example, like, Order and OrderItem, Order has a total amount which is tightly coupled to all OrderItems in same order. Cascading update OrderItem should bump up version column at Order table, otherwise, things just out of sync. That makes sense.
This complies with aggregate root pattern,as one of the aggregate rules is:
When a change to any object within the Aggregate boundary is committed, all invariants of the whole Aggregate must be satisfied.
For me, it means that the version at root level should reflect changes on any child within the same aggregate.
Now the real question is, are email, telephone and address under the same person’s aggregate? If you are shocked to see the person’s version changed by it’s email/telephone/address modification in your app, just don’t map this relationship as cascade save-update, calling Session.SaveOrUpdate(personEmail) instead of Session.SaveOrUpdate(person).
Before setting cascade save-update, read through aggregate root pattern.
Note, I found a very confusing fact, if parent entity has no version column properties defined, cascade save-update will bypass this behavior, but, if another child entity with version column is mapped as NotLazyLoad collection under the save root, NHibernate will try to set the version column on that child entity!