Nevertheless this is an interesting idea which I am going to pursue (if anybody happens to know the solution, either how to, or that it is not possible at all, of course I'll be grateful for an advice, before I dive into that).
Another way, the one I've tried to exploit so far, was implement the behaviour app-side:
I believe that is the only way to absolutely ensure this. I don’t think you can make a rock-solid guarantee from the app code level.
Can't I? That's bad.
So far, I thought this very simple concept should be rock-solid, but probably I am overlooking something of importance, as so often:
=== eo's entity locks on the someRelationship FK (among others) ===
OSC.lock() // possibly superfluous; simplifies situation by serializing intra-instance
try {
ec.unlock(); ec.lock() //* to make sure we get changes from other ECs now, by your excellent advice
def rel=eo.someRelationship() // in DB there might be a newer value (saved meantime by another instance)...
def attr=rel.someAttribute() // ... but it is not possible that in DB is an _older_ value than this
if (TEST(attr,newAttributeValue)) {
def new=EOUtilities.createAndInsertInstance(eo.editingContext(),'SomeRelationshipTarget')
new.setSomeAttribute(newAttributeValue) // once set, I NEVER change this value
eo.addObjectToBothSidesOfRelationshipWithKey(new,'someRelationship')
eo.editingContext().saveChanges() // catching optimistic exceptions and repeating the process if they happen
}
} finally {
OSC.unlock()
}
===
My reasoning is that
- intra-instance, consistency is ensured by locked (single) OSC and by //* -- I am sure that I see the latest eo.someRelationship and its rel.someAttribute before saving, and thus the TEST is reliable; my own instance, even with concurrent requests, can't
do anything wrong
- inter-instance, the optimistic locking based on someRelationship FK should prevent saving in case any other instance succeeded to save its own new attribute meantime.
What am I overlooking, how can this pattern fail?