djmarkert wrote:
Otis,
I found the following information in the 'Handling Exceptions' topic in the help manual which sheds light on this issue:
ORMConcurrencyException. This exception is thrown when, during a recursive save, a save fails, i.e. doesn't affect any rows. This can be caused by the fact that the row being updated is already deleted, or the predicate created by the set ConcurrencyPredicateFactory or the passed in predicate caused a failure of the update due to a concurrency violation. This exception is only thrown during a recursive save. If a save is not recursive, the save just fails and false is returned. This is done for backwards compatibility, as this exception is introduced after the development of recursive saves. The exception will terminate the transaction started during a recursive save and will therefore make a recursive save action completely atomic.
Well, that would explain the behavior I'm seeing
.
Is the need for backward compatibility really that strong to keep the .Save() working as is (returning false)?
Yes, as changing this would break a lot of applications because all of a sudden they'll get an exception instead of a return value. This is an old debate: return values vs. exceptions, and I'm in teh camp which says that exceptions shouldn't be used for flow control, but should be used to inform the caller code of an exceptional (hence the name IMHO
) situation. The save() also fails if no concurrencypredicatefactory is used by the record is deleted for example from the database.
With a non-recursive Save, and it fails, you know which entity failed, the one you called Save() on. In a recursive save, you can't say that. Also the recursive save is always run inside a transaction, so to make that rollback the inner save somewhere deep in the recursion has to throw an exception.
So rule of thumb: always check return values and act accordingly, and recursive saves throw exceptions because of transactional rollback/commit issues.