You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user-java@ibatis.apache.org by "Shannon, Bryan" <BS...@Tribune.com> on 2008/04/28 18:58:51 UTC

Poll: comparing old and new beans before persisting

I am fully aware that iBatis isn't a full ORM (and thank goodness it's
not)...
 
But there are still places where, in a fully normalized db schema, there
isn't a one bean per table-row in the database...
 
There are often one to many relationships and join tables, etc.  I'm
wondering if/how anyone else out there has tried to make determining
which rows to insert/update/delete an easier task.
 
Do you compare the beans (before and after) property-by-property? 
 
Did you write convenience functions that compare the list properties of
to beans to each other to figure out which is an insert, an update, or a
delete?
 
I'm asking this list because I've thrown some convenience classes
together that make it much easier to compare an old bean with a new bean
and do the appropriate ibatis stuff...
 
It basically is used something like this:
 
// Assuming a bean that has a collection property of "favoriteFoods":
new CollectionPersister(sqlMap, oldBean, newBean, "favoriteFoods",
"MyMap.deleteFavoriteFood", "MyMap.updateFavoriteFood",
"MyMap.insertFavoriteFood").persist();
 
By default, the persister compares the old values and new values for the
favoriteFoods property, and calls the appropriate sql map with that
favorite food bean as a parameter...
 
Of course, sometimes sometimes you need to send in a map or some other
bean as a parameter to the map to link to entities together, so I have
hooks that allow me to override this basic functionality:
 
 
new CollectionPersister(sqlMap, oldBean, newBean, "favoriteFoods",
"MyMap.deleteFavoriteFood", "MyMap.updateFavoriteFood",
"MyMap.insertFavoriteFood") {
 
    // Overriding the default behavior of sending a Food element to the
update map as a parameter; it needs a map instead...
    public void getUpdateMapParam(Object listElement) {
        Map tmp = new HashMap();
        tmp.put("person_id", personId);
        tmp.put("favorite_food_id", ((Food)listElement).getId());
        return tmp;
    }
 
}.persist();
 

The persister is extendable and has some complex logic that determines
which elements of the list were actually inserted/updated/deleted.
 
Has anyone else done things like this?  I was able to take about 1000
lines of my dao and shrink it into about 1 line per collection property
(I have a huge object graph). 
 
Anyone else interested?  As I started to retrofit a dao that has grown
with age and saw the usefulness of something like this, I thought of you
guys on the list. :-)
 
I don't know if anyone else out there has tried to solve the problem of
trying to only update what needs to be updated, or does this old vs. new
comparison.  There are only a few ways to handle this problem in general
(it seems to me):
 
1) Just always update, even if it doesn't change.  "Drop and Swap"
collections (that are persisted to your join tables in the db).
2) Somehow add properties to your beans to keep track of what changed (a
"dirty flag")
3) Do what hibernate does and pollute your bean with magical proxies,
which forces you to have your hibernate+100 dependencies on your client
tier's classpath.  (GRRR; a Swing GUI in my case!)
4) Send the old and the new and compare them, the more automated, the
better.
 
Tell your stories!  I'm sure someone else out here would like to hear
them.
 
Thanks!
-Bryan Shannon
Tribune Media Services
 

RE: Poll: comparing old and new beans before persisting

Posted by "Shannon, Bryan" <BS...@Tribune.com>.
Actually, I send in just the old and new beans;  Locking can either be
pessimistic or optimistic and is at the "record" level.  Since the utils
are all callback/template based, you could potentially check the value
for the list in the database in your callback method if you need to.

I have found that in many of my data entry cases, optimistic locking at
the record level is fine; a simple ("before you save, make sure that the
record in the database doesn't have a more recent timestamp than the one
you loaded as a last update timestamp")  

In my specific case, we then let the user decide whether or not to save
their changes anyway, (possibly) overwriting the other user's changes.
[that ability is permission based].  (again, the overwrite would only
meddle with the other user's changes if they changed the exact same
collections as we did, since the util class only persists things that
are different.)

The actual comparison for the list properties goes a little like this
(just a rough outline):
If there is an object in oldList, but not in newList, then it is an
insert.
If there is an object in newList, but not in oldList, then it is a
delete.
If there is an object in oldList and newList that have the same PK but
not the same content, then it is an update.  (the way it actually
determines this is customizable).


Optionally, reordering fields in a list between old an new can
optionally be considered an "update", since there are cases when our
join tables have something like:

Person_id	favorite_food_id	sequence
---------	----------------	--------
13423		42			1
13423		54			2

(Etc.)



-----Original Message-----
From: Chris Marshall [mailto:chris@campsbayterrace.com] 
Sent: Tuesday, April 29, 2008 7:00 AM
To: user-java@ibatis.apache.org
Subject: Re: Poll: comparing old and new beans before persisting

Hi Bryan,
If I understand you correctly you implement a form of field level
optimistic locking using three versions of a bean - the original bean,
the modified bean, and the currently persisted bean (which may have been
changed by others since the original bean was read). By comparing the
properties of each you update only those properties that have changed,
presumably only if they have not been changed by others in the meantime.
Is this correct?
Regards Chris

Re: Poll: comparing old and new beans before persisting

Posted by Chris Marshall <ch...@campsbayterrace.com>.
Hi Bryan,
If I understand you correctly you implement a form of field level
optimistic locking using three versions of a bean - the original bean,
the modified bean, and the currently persisted bean (which may have
been changed by others since the original bean was read). By comparing
the properties of each you update only those properties that have
changed, presumably only if they have not been changed by others in
the meantime. Is this correct?
Regards Chris