Hibernate Books

All times are UTC - 5 hours [ DST ]



Post new topic Reply to topic  [ 28 posts ]  Go to page Previous  1, 2
Author Message
 Post subject:
PostPosted: Fri Jul 11, 2008 4:46 pm 
Beginner
Beginner

Joined: Thu Mar 18, 2004 8:11 am
Posts: 38
Location: Italy
gavin wrote:
usually wanting to delete then reinsert is a sign that you are trying to use Hibernate in the wrong way.


It seems to me that you are expressing the concept that even the natural key of an object has to be immutable, which I think is wrong.

Removing an object from a persisted collection and adding there another with the same natural key BUT DIFFERENT PK is a legit operation. Why shouldn't it be allowed? Otherwise, what is the meaning of stressing about the need and importance of an immutable PK?

Thereby, in order to overcome UK problems, it seems evident to me that DELETEs should be performed before INSERTs. Why is the Hibernate team so reluctanct in accepting this? What is the problem?

Also note that just removing, then flushing the session, then inserting is not always a solution. Think, in example, to the case of a Long-running Conversation with the "session-per-conversation" pattern (cap. 11.1.2). In that case one should "flush()" only when the whole unit of work is completed. You can't simply do it when you like... This would mean that one has to store the add()s issued to a persisted collection somewere, in order to issue them at the end of work unit after the first flush. This seems suboptimal to me since it is part of what an Hibernate collection is supposed to do...

Again, what is the problem with respecting the delete-update-insert sequence? I'm missing it.

_________________
Giampaolo Tomassoni
Italy


Top
 Profile  
 
 Post subject: No answer yet
PostPosted: Mon Feb 23, 2009 4:06 pm 
Newbie

Joined: Mon Feb 23, 2009 3:57 pm
Posts: 1
This issue was raised a long time ago and there still doesn't appear to be an answer to one simple question:

Why does Hibernate perform Inserts before Deletes?

Forget about all the rest of the dialog on this thread, but please give a good reason for this behavior. I'm sure there is one that just needs to be explained.

Thanks,
Smitty


Top
 Profile  
 
 Post subject: Re: DELETE then INSERT in collection - Order of executed SQL
PostPosted: Thu Sep 24, 2009 6:43 pm 
Newbie

Joined: Thu Jun 12, 2008 1:14 am
Posts: 4
I agree. Please address this issue. I need an index on my key+listIndex to prevent hibernate from messing up my data and then never recovering from the dups.


Top
 Profile  
 
 Post subject: Re: DELETE then INSERT in collection - Order of executed SQL
PostPosted: Fri Nov 20, 2009 8:05 am 
Beginner
Beginner

Joined: Wed Jun 28, 2006 2:24 pm
Posts: 30
Location: Brazil
I have the same problem! I just want an unique constraint on foreign key and index column in my table. So I need that delete be performed before insert. I don't want break my database integrity because Hibernate can't do the right thing! Apology, but I think that this is a defect.


Top
 Profile  
 
 Post subject: Re: DELETE then INSERT in collection - Order of executed SQL
PostPosted: Wed Jan 20, 2010 1:09 pm 
Newbie

Joined: Wed Jan 20, 2010 12:55 pm
Posts: 2
Gavin's advice regarding the synchronization of the UK and PK is the only thing that worked for me. You must define a composite key that matches your unique constraint. I had the same problem with the inserts and deletes not occurring in the correct order (I was receiving a constraint violation when I did a delete and then an insert within the same transaction). I had a synthetic PK defined for the table, and an additional UK with three separate columns involved. The inserts and deletes occurred in the correct order only after I dropped the synthetic PK column and added the necessary annotations related to integrating an @EmbeddedId that matched the UK. This link shows you what's needed to add the composite key and it's annotations:

http://www.ibm.com/developerworks/java/library/os-hibernatejpa/index.html

This link was also helpful:

http://opensource.atlassian.com/projects/hibernate/browse/HHH-2801


Top
 Profile  
 
 Post subject: Re: DELETE then INSERT in collection - Order of executed SQL
PostPosted: Thu Jan 21, 2010 8:45 am 
Newbie

Joined: Wed Jan 20, 2010 12:55 pm
Posts: 2
Just one additional comment that may be helpful. I did have to disable input for all of the UC (PK) attributes on the UI. I had to take the approach where I let the user add and delete existing rows, but not allow them to update any of the UC attributes (they can update other attributes, just not the ones that are part of the PK). The only time the user can alter the UC attributes is during an add (this includes validation on the backend for duplicated keys).

This makes sense, as when you change the value of one of the PK attributes, an update cannot be successful since the row can no longer be located against the original key.


Top
 Profile  
 
 Post subject: Re: DELETE then INSERT in collection - Order of executed SQL
PostPosted: Thu Jan 21, 2010 11:08 am 
Expert
Expert

Joined: Tue Jun 16, 2009 3:36 am
Posts: 988
I never really understood why Hibernate don't simply executes all actions in the same order they were enqueued.
I suppose most other JPA and JDO providers implement the write-behind mechanism respecting chronological order.

Making this kind of separated queues (inserts, updates, deletes etc.) in my opinion makes only sense
for exploiting the jdbc batching-feature with the maximum of efficiency.
(configuring hibernate.jdbc.batch_size > 0)


Top
 Profile  
 
 Post subject: Re: DELETE then INSERT in collection - Order of executed SQL
PostPosted: Mon Sep 05, 2011 1:12 pm 
Beginner
Beginner

Joined: Sat Sep 17, 2005 6:50 am
Posts: 23
I've hit the same problem. It took some time to realize, what is actually happening.
Unfortunately, as cyboc mentioned, I can't use composite IDs and I also can't call session.flush() in-between collection.clear() and collection.add() as I don't have Hibernate session at that point (and getting it will break the separation of DAO and processing module).
So, alas, I have to write a code, that would actually merge newly created collection items into existing collection. Perhaps that's for the best, as there will be a bit less load on DB.
For those, who are interested, two relative topics on StackOverflow: 1 and 2.


Top
 Profile  
 
 Post subject: Re: DELETE then INSERT in collection - Order of executed SQL
PostPosted: Thu Nov 17, 2011 2:31 am 
Newbie

Joined: Mon Oct 11, 2010 5:24 pm
Posts: 6
I routinely have to merge deep object graphs originating from external systems (lacking my IDs), and it is almost guaranteed that any update will contain at least one of these transient-but-naturally-matches-a-persistent-collection-member merge landmines. I have created a piece of disgusting, hacky code to deal with this issue (below) by recursively digging through the graph to find and re-ID transient collection members that match the natural ID of an existing member. I follow this up with a merge() and update() and this seems to work OK.

This is just one of many issues that are starting to feel like punishment for having this use case. Life is great when every object you need to persist either originated from the DB or is new, but sadly I have to deal with matching detached entities by natural ID all over the place. I am surprised to see composite PKs posed as a solution since my experience trying to use them was that the Hibernate team's general attitude was that they weren't recommended and were mostly only supported for legacy systems.

I am obviously not the only one to feel stuck between these options: https://hibernate.onjira.com/browse/HHH-2896. Unified support for ID and natural ID across the entire persistence API would be an amazingly powerful tool, but unfortunately I have seen no acknowledgement that this is even an issue much less an idea of if/when it will be implemented (see the crickets chirping over here: https://forum.hibernate.org/viewtopic.php?f=1&t=1011626).

I have opted for surrogate PKs in the end. My thoughts on the painful experience:

Composite PKs are great for detached objects, but:
-Your model gets flooded with inherited composite IDs
-Trying to remedy this by mapping child FKs to a scalar UK in a composite ID parent buys you this bug (3.6): https://forum.hibernate.org/viewtopic.php?f=1&t=1011670
-You lose envers auditing support
-Based on the above 2, you can probably expect to find other holes in stated behavior of Hibernate when it comes to composite PKs
-Your DBA hates you
-Performance takes a hit from the sheer volume of repeated information

On the other hand if you use surrogate PKs when you have to deal with detached objects:
-You need to either hack something up like I did or manually pick though your entire graph to weed out the transients that match persistent collection members
-You lose session.get() and 2nd level caching by natural IDs. Only option left is query caching. Not very fun if, like me, you are receiving 10,000,000s of detached objects and needing to resolve them quickly against potential DB or session matches. I have resorted to managing my own caches of natural ID-ed objects in EHCache
-Defining natural UKs containing an FK parent ID gets awkward


Code:
   @SuppressWarnings("rawtypes")
   protected void reattachVolatileCollections(Object detached, Object persistent, Class<?> clazz, Set<Object> alreadyProcessed) throws Exception{

      if (!alreadyProcessed.contains(detached)){

         Session session = sessionFactory.getCurrentSession();         
         ClassMetadata md = sessionFactory.getClassMetadata(clazz);      

         if (md != null){
            for (String prop : md.getPropertyNames()){

               PropertyDescriptor pd = PropertyUtils.getPropertyDescriptor(detached, prop);      

               if (Collection.class.isAssignableFrom(pd.getPropertyType()) || Map.class.isAssignableFrom(pd.getPropertyType())){                           

                  Object dets = md.getPropertyValue(
                        detached,
                        prop,
                        session.getEntityMode());

                  Object dbs = md.getPropertyValue(
                        persistent,
                        prop,
                        session.getEntityMode());

                  Iterator it = null;
                  if (Collection.class.isAssignableFrom(pd.getPropertyType())){
                     it = ((Collection)dets).iterator();
                  }else{
                     it = ((Map)dets).values().iterator();
                  }

                  while (it.hasNext()){

                     Object det = it.next();                  

                     Iterator dbit = null;
                     if (Collection.class.isAssignableFrom(pd.getPropertyType())){
                        dbit = ((Collection)dbs).iterator();
                     }else{
                        dbit = ((Map)dbs).values().iterator();
                     }

                     while (dbit.hasNext()){

                        Object db = dbit.next();
                        if (db.equals(det)){
                           md.setIdentifier(
                                 det,
                                 md.getIdentifier(db, session.getEntityMode()),
                                 session.getEntityMode());   
                           reattachVolatileCollections(det,db,getTrueType(det),alreadyProcessed);
                        }
                     }
                  }

               }
            }
         }
      }
   }


Top
 Profile  
 
 Post subject: Re: DELETE then INSERT in collection - Order of executed SQL
PostPosted: Thu Nov 17, 2011 3:42 pm 
Beginner
Beginner

Joined: Sat Sep 17, 2005 6:50 am
Posts: 23
alecbritton wrote:
I routinely have to merge deep object graphs originating from external systems (lacking my IDs), and it is almost guaranteed that any update will contain at least one of these transient-but-naturally-matches-a-persistent-collection-member merge landmines. I have created a piece of disgusting, hacky code to deal with this issue (below) by recursively digging through the graph to find and re-ID transient collection members that match the natural ID of an existing member. I follow this up with a merge() and update() and this seems to work OK.

This is just one of many issues that are starting to feel like punishment for having this use case. Life is great when every object you need to persist either originated from the DB or is new, but sadly I have to deal with matching detached entities by natural ID all over the place. I am surprised to see composite PKs posed as a solution since my experience trying to use them was that the Hibernate team's general attitude was that they weren't recommended and were mostly only supported for legacy systems.

I am obviously not the only one to feel stuck between these options: https://hibernate.onjira.com/browse/HHH-2896. Unified support for ID and natural ID across the entire persistence API would be an amazingly powerful tool, but unfortunately I have seen no acknowledgement that this is even an issue much less an idea of if/when it will be implemented (see the crickets chirping over here: https://forum.hibernate.org/viewtopic.php?f=1&t=1011626).

alecbritton, thank you for code snippet! I would be happy if that code can help in the case with collections (first transient entities are persisted and then the collection elements are removed). If your code is applied just before passing the parent object to "saveOrUpdate()", then the transient entities will be re-associated, but collection elements will be removed anyway.

The only alternative I see now is to wrap Hibernate collections into custom collections and flush the session on collection clear().


Top
 Profile  
 
 Post subject: Re: DELETE then INSERT in collection - Order of executed SQL
PostPosted: Thu Dec 01, 2011 11:24 am 
Newbie

Joined: Tue Jul 15, 2008 8:27 am
Posts: 12
Location: Germany
IMHO the behaviour of reordering the SQL-statements is not acceptable and should be offered as optional optimization-configuration parameter and should be clearly described. Especially since it forces a specific way to use PKs (and many people simply prefer surrogate primary keys to natural keys or any kind of composite pks) - making the world harder for people who model top-down (starting with the ER-Model) - as this thread shows this behaviour is a real pitfall, since the expected (progammed) semantics of your code is actually changed (there is normally a reason why I do x first and then y!).

And saying "you are using hibernate the wrong way" is way too easy to do and neither nice nor helpful.

Cheers, Arndt

PS: To sum it up: A config-falg to en-/disable the reordering of sql-statements would be greatly appreciated.


Top
 Profile  
 
 Post subject: Re: DELETE then INSERT in collection - Order of executed SQL
PostPosted: Thu Dec 01, 2011 1:08 pm 
Newbie

Joined: Thu Dec 01, 2011 12:53 pm
Posts: 1
If you happen to use Oracle, this issue may be solved by using deferrable index constraints as in:
Code:
create table "B"
(
    "ID" number(18, 0) not null,
    constraint PK_B primary key ("ID")
);
create table "A"
(
    "ID" number(18, 0) not null,
    "FK_B" number(18, 0) not null,
    "RANK" number(5, 0) not null,
    -- ...
    constraint PK_A primary key ("ID"),
    constraint FK_A_B foreign key ("FB_B")
        references "B" ("ID"),
    constraint UK_A_FB_RANK unique ("FB_B", "RANK") deferrable initially deferred
);


Ref: http://docs.oracle.com/cd/B28359_01/server.111/b28286/clauses002.htm#CJADJGEC


Top
 Profile  
 
 Post subject: Re: DELETE then INSERT in collection - Order of executed SQL
PostPosted: Thu Dec 01, 2011 2:42 pm 
Newbie

Joined: Tue Jul 15, 2008 8:27 am
Posts: 12
Location: Germany
Yes, thank you, I have read the post on oracle, in fact starting with Postgres 9.1 (maybe 9.0) we can do this also with Postgres, but we are still on 8.4 and anyways I think it would be good to offer a way to configure this behaviour, since it also (using prepared statements) makes debugging the actual SQL queries nearly impossible - since you do not see the values that will be set _AND_ you cannot rely on the order you issue your SQL-statements.

Thanks anyways for the hint on Oracle ;) - the DB was actually the first part I was looking into...

Cheers, Arndt


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 28 posts ]  Go to page Previous  1, 2

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.