Chuck, >> Actually _this_ should not be weird, this should be quite a normal code; the >> only requirement is that check-and-save, i.e., conceptually, >> >> === >> if (TEST(eo.someRelationship().someAttribute(),newAttributeValue)) { >> def >> new=EOUtilities.createAndInsertInstance(eo.editingContext(),'SomeRelationshipTarget') >> new.someAttribute=newAttributeValue >> eo.editingContext().saveChanges() >> } >> === >> >> so that I can be absolutely sure that nobody stores an attribute value which >> -- at the moment of COMMITTing the appropriate INSERT -- would not pass the >> TEST
Alas, since the TEST is (slightly) more complex than A!=B, I can't use a UNIQUE db restraint. One way would be to twist the DB to do the complete restraint to me, something like to a pseudo-code “inserted_row.attr>=MAX(SELECT attr FROM this_table WHERE another_attr.isValid) AND couple more similar conditions” -- frankly I am not sure whether the database (FrontBase) can do that at all, and if it can, definitely I don't know how to. 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? In fact, to decrease the probability of the optimistic locking exception, I force re-fetch (in my new multi-instance code, not the single-instance old one), like this: === OSC.lock() // precisely same as above try { ERXEC tempec=ERXEC.newEditingContext() tempec.fetchTimestamp=System.currentTimeMillis() // due to this, I don't need "ec.unlock(); ec.lock()", for... def tempeo=eo.localInstanceIn(tempec) def rel=tempeo.someRelationship() // ... whatever was cached in ECs, current FK from eo's table gets fetched now def attr=rel.someAttribute() // ... just like its attribute from rel target's table if (TEST(attr,newAttributeValue)) { // precisely same as above (the only difference is that the values are newer... def new=EOUtilities.createAndInsertInstance(tempec,'SomeRelationshipTarget') new.setSomeAttribute(newAttributeValue) tempeo.addObjectToBothSidesOfRelationshipWithKey(new,'someRelationship') tempec.saveChanges() // ... and thus the probability of optimistic locking exception (caused by different relationship FK) is smaller (though of course not zero) } } finally { OSC.unlock() } === Are even these patters unsafe? Why? Thanks a big lot, OC _______________________________________________ Do not post admin requests to the list. They will be ignored. Webobjects-dev mailing list (Webobjects-dev@lists.apple.com) Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/webobjects-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com