Warning after being up for over 24 hours, this post is probably laced with spelling errors, poor grammar, and plot holes.
In talking with a friend of mine today .. he brought up an interesting scenario that can come up when dealing with objects in an identity map and observers of these objects. The issue comes in when dealing with the transactional nature of the observations as they are maintained by an external broker.
While I'd like to think I have had an original thought on the subject ... I am quite sure someone else has done this before :)
Although in the last example I used mementos in order to save state, for this problem one is better off operating on copies of the objects within the map. This is another very well known method of allowing for transactional graph handling. By returning a copy of the object we allow the client to do anything they wish to the object without damaging the original, all clients receive a copy of the current object. When an object is committed we copy it over the original object in the graph after it has successfully completed it's transaction. If we wanted to we could use either optimistic or pessimistic locking in this example relatively easily.
The gotcha in his case though was the observers ... Let's say that I add a new observer to a temp object, the original thought was to proxy that request to the main mapped object. This has a few issues ..
1) An observer could receive messages before it's object had ever actually been committed, this could result in all sorts of fun behavior.
2) A rollback operation becomes fun because one would now have to remove the registration for the subscription
3) a subscription to one temp object could receive updates from another
In the case discussed, guids were being used to uniquely identify objects ... The solution I ended up with was to modify the event broker to add a new method Depreciate(guid, guid). When the commit operation occurred on the graph, the temporary object would be copied over the original object, during this process a call would be made to the broker telling it to depreciate the first object with the second. The depreciation operation quite simply moves all subscriptions from object x to object y making object y the publisher for the combined subscription set. Since this is happening within the transaction the first problem above is solved ... For the second issue, in the case of a rollback you simply do not depreciate the original object, as such the subscriptions that have been made to the temporary object just go away when the temporary object is garbage collected. In the last case, since each object has its own registrations that are aggregated during the commit any subscriptions which were meant to only apply to an object in its temporary state are kept isolated.
These were just my quick thoughts on how to handle this situation I would love to hear others.
Update: After implementing a quick version of this to be sure everything worked, I changed the design slightly to avoid a coupling between the identity map and the broker. Instead of having the identity map call the broker I allowed injection of steps to the commit process (DuringCommit) as such calling code can register the depreciation code with the identity map.