• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Never save objects which don't pass a test (was: searching for a weird deletion)
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Never save objects which don't pass a test (was: searching for a weird deletion)


  • Subject: Re: Never save objects which don't pass a test (was: searching for a weird deletion)
  • From: Chuck Hill <email@hidden>
  • Date: Fri, 20 Feb 2015 18:37:44 +0000
  • Thread-topic: Never save objects which don't pass a test (was: searching for a weird deletion)



On 2015-02-20, 9:27 AM, "OC" wrote:

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.

I think you can do it as a Check constraint.  It needs to be a boolean _expression_, but I am not sure it can include selects.  A quick experiment would show if it can.



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?

I am not quite following the requirements.  Is it unique only for this object or for all objects?

Chuck



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      (email@hidden)
Help/Unsubscribe/Update your Subscription:

This email sent to email@hidden

  • Follow-Ups:
    • Re: Never save objects which don't pass a test (was: searching for a weird deletion)
      • From: OC <email@hidden>
    • Re: Never save objects which don't pass a test (was: searching for a weird deletion)
      • From: OC <email@hidden>
References: 
 >searching for a weird deletion (From: OC <email@hidden>)
 >Re: searching for a weird deletion (From: Ramsey Gurley <email@hidden>)
 >Re: searching for a weird deletion (From: OC <email@hidden>)
 >Re: searching for a weird deletion (From: Chuck Hill <email@hidden>)
 >Never save objects which don't pass a test (was: searching for a weird deletion) (From: OC <email@hidden>)

  • Prev by Date: WO app building (was: searching for a weird deletion)
  • Next by Date: Re: Never save objects which don't pass a test (was: searching for a weird deletion)
  • Previous by thread: Never save objects which don't pass a test (was: searching for a weird deletion)
  • Next by thread: Re: Never save objects which don't pass a test (was: searching for a weird deletion)
  • Index(es):
    • Date
    • Thread