On Thu, Jun 19, 2014 at 8:26 AM, Kevin Sutter <sutter_at_us.ibm.com> wrote:
> Hi Laird,
> Your write-up and the referenced SO post were helpful in understanding the
> dilemma of JPA merge and the DIY approach. Unfortunately, I couldn't make
> the leap to your proposal:
>
> > Would it make sense to add a find() variant that takes both an ID
> > and a version and throws an OptimisticLockException if a persistent
> > entity with those coordinates does not exist? Or am I missing
> > something more fundamental somewhere in the API that would explain
> > why this is not needed?
>
> Specific to your request, how is this proposal different from just doing
> the normal find() operation with the ID and then just comparing the version
> that is returned with the version you are interested in? As your previous
> paragraph suggested... This approach avoids the exception processing
> overhead as well, which I am not in favor of. You are just trying to move
> this version compare logic from the user to the JPA provider? Hmmm...
> Just not seeing the advantage here.
>
That's all fair, I suppose (although I'm not understanding the exception
processing overhead? wouldn't the find() call just return null? or do you
mean the OptimisticLockException which you throw yourself in DIY merges
today?); what I really *should* have written was I'd like a *getReference()*
variant that takes an ID and a version. Does that make more sense? Then a
state fetch wouldn't have to happen at all.
To spell it out:
final Person p = em.getReference(Person.class, 32 /* ID */, 3 /* version
*/);
if (p != null) { // if you're not into exceptions :-)
// if we get here we're good; no intervening edits have happened
// if we DON'T get here, it's because there's been a concurrency issue
// note as well that p's state has not been fetched (apart from his PK
and version)
p.setLastName("Nelson"); // begin DIY merging
// this should just result in an UPDATE PERSON SET LASTNAME = 'Nelson'
// no additional SELECTs
}
From a philosophical perspective, I guess there are a couple things in play:
1. An entity's "coordinates" really are the combination of its primary
key and its version (if it has one, of course). It seems like that should
be reflected in the API somewhere somehow. Even when you do a simple
find() call, you're implicitly adding, "...if it's the latest version,
of course" to the semantics of the query.
2. Except in the case of DIY merges, I don't think there's another case
in all of JPA where you have to do something with the version yourself as a
programmer. It is a field that is managed by the JPA provider, updates to
it are forbidden, it is only useful for comparing for equality, etc. I'm
not claiming anything hard or technical here; just that it "feels wrong" to
have to reach into an entity, grab this immutable, opaque, provider-managed
thing and compare it against the immutable, opaque, provider-managed thing
that was previously handed to you at some point...feels like the wrong
actor is being made to perform these tasks just so he doesn't shoot his own
leg off.
Best,
Laird
--
http://about.me/lairdnelson