-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 15 posts ] 
Author Message
 Post subject: Hibernate merge error
PostPosted: Wed Apr 26, 2006 10:53 am 
Newbie

Joined: Mon Apr 24, 2006 2:01 pm
Posts: 13
Hello,

I'm getting the following error on the merge:


15:28:36 ERROR an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session)
org.hibernate.AssertionFailure: entity was not detached
at org.hibernate.event.def.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:201)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:102)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:544)
at org.hibernate.engine.Cascades$6.cascade(Cascades.java:176)
at org.hibernate.engine.Cascades.cascadeAssociation(Cascades.java:771)
at org.hibernate.engine.Cascades.cascade(Cascades.java:720)
at org.hibernate.engine.Cascades.cascadeCollection(Cascades.java:895)
at org.hibernate.engine.Cascades.cascadeAssociation(Cascades.java:792)
at org.hibernate.engine.Cascades.cascade(Cascades.java:720)
at org.hibernate.engine.Cascades.cascade(Cascades.java:847)
at org.hibernate.event.def.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:264)
at org.hibernate.event.def.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:223)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:102)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:54)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:535)




I have a graph of object that is coming from the client and the server needs to merge with the database. The incoming objects are not yet loaded in the session.

The top level object is already exists in the DB but child is not (new object). I have cascade="all,delete-orphan" specified in the parent object mapping.

When I call session.merge (topLevelObject) will the child saved to the database ? But getting the above error

Any help would be greately appreciated.


Thanks


Last edited by a_shanmugam on Fri Apr 28, 2006 6:52 am, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 26, 2006 10:32 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
Session.merge is used when the object you want to save is detached. Use Session.update, or simply Session.flush, when the object is still attached. Something simple like this will do:
Code:
if (sess.contains(obj))
{
  sess.update(obj);
}
else
{
  sess.merge(obj);
}


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 27, 2006 12:04 am 
Newbie

Joined: Wed Apr 26, 2006 11:46 pm
Posts: 2
tenwit wrote:
Session.merge is used when the object you want to save is detached. Use Session.update, or simply Session.flush, when the object is still attached. Something simple like this will do:
Code:
if (sess.contains(obj))
{
  sess.update(obj);
}
else
{
  sess.merge(obj);
}


I don't think so ,I hava a test for session merge() method like that:

Code:
     obj=session.get(obj.class,id);
     s.contains(obj);
     session.update(obj);

it's no mistake and the s.contains(obj) is true,is it?


regards


wangzk


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 27, 2006 12:08 am 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
I think there's something wrong with what you've just posted. Can you post it again? Try the preview button, too. I'd expect to see a conditional statement in there.. "s.contains(obj);" is a pointless statement, you must have left something out.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 27, 2006 11:41 am 
Newbie

Joined: Mon Apr 24, 2006 2:01 pm
Posts: 13
OK. After upgrading to Hibernate version 3.1.3 now I have a different issue. for some reason when I do the merge, it inserts the new objects to the database right away. That is OK, but it does not reconize the ID fields those already been set on the object and it tries to insert null values to those fields. Here is my little code snippet.


Code:
                    if(ObjectManager.currentSession().contains(participant)){
                        ObjectManager.currentSession().update(participant);
                    } else {
                        ObjectManager.currentSession().merge(participant);
                    }


Here the object manager is a custom class it mearly delegates to Hibenate.

The participant object has a collection of address objects. The following is the configuration details of the parent object ie participant.

Code:

      <!-- collection mapping -->
      <set name="addresses" table="participant_addr" inverse="true" cascade="all,delete-orphan">
         <key column="participant_id" />
         <one-to-many class="ParticipantAddress" not-found="ignore" />
      </set>



And the address object has the following configuration.

Code:

   <class name="ParticipantAddress" table="participant_addr">
      <composite-id>
         <key-property name="ownerNumber" column="owner_number" />
         <key-property name="participantId" column="participant_id" />
         <key-property name="addressType" column="address_type" />
      </composite-id>

      <property name="address1" column="address_1" />
      <property name="address2" column="address_2" />
      <property name="city" column="city" />
      <property name="state" column="state" />
      <property name="country" column="country" />
      <property name="zip" column="zip" />

   </class>



the participant object is construted in the client tier and that does not know about the Hibernate session. It comes to server via a Session Bean method and being merged to the session.

Question is NO SURE why the Hibernate did not recognize the id column data that is already in the object and tries to insert null values on the merge call.


ANY HELP WILL BE APPRECIATED AND I WILL LEAVE A GOOD RATING :)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 27, 2006 7:08 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
You don't say which object it is that is having the null values inserted. You describe the ParticipantAddress class without saying why you need to describe it, so I'm inferring that that's the class that has the save issues?

You have inverse="true" on the <set> element. This means that when you save a Participant object, no ParticipantAddress objects will be created or deleted. This overrides the cascade="all, delete-orphan" cascade: it effectively demotes the cascade to just "update". That might be your problem.

Another issue you have, though it's not causing this problem, is your merge line. Session.merge returns the persistent instance of the detached parameter. In 99% of cases, this is the instance that you'll want to from then on. So your code should almost certainly be:
Code:
participant = ObjectManager.currentSession().merge(participant);


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 27, 2006 9:42 pm 
Newbie

Joined: Wed Apr 26, 2006 11:46 pm
Posts: 2
tenwit wrote:
I think there's something wrong with what you've just posted. Can you post it again? Try the preview button, too. I'd expect to see a conditional statement in there.. "s.contains(obj);" is a pointless statement, you must have left something out.

I'm sorry for making mistake that the 's' actually is 'session',and what I want to say is that the merge method could use for PO too,
sorry.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 27, 2006 10:06 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
I meant that s.contains(obj), or session.contains(obj), does nothing. It's a test method with no side effects. You have to look at the return value, otherwise there's no point in calling it. "if (s.contains(obj)) s.update(obj);" is a sensible statement. "s.contains(obj);" is not.

What is PO?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 27, 2006 10:23 pm 
Newbie

Joined: Mon Apr 24, 2006 2:01 pm
Posts: 13
Sorry for not clearly stating my issue.

Here are the tables:
Code:
Table 1: participant


Column name          Type                                    Nulls

owner_number         integer                                 no
participant_id       integer                                 no

Table 2: particpant_addr
Code:
Column name          Type                                    Nulls

participant_id       integer                                 yes
owner_number         integer                                 yes
address_type         char(1)                                 yes
address_1            char(30)                                yes
address_2            char(30)                                yes
city                 char(20)                                yes
state                char(10)                                yes
country              char(25)                                yes
zip                  char(10)                                yes



Mapping:

Code:
   <class name="Participant" table="participant" lazy="false">
      <id name="participantId" type="integer" column="participant_id" unsaved-value="0">
         <generator class="assigned" />
      </id>


      <set name="addresses" table="participant_addr" cascade="all,delete-orphan">
         <key column="participant_id" />
         <one-to-many class="ParticipantAddress" not-found="ignore" />
      </set>

   </class>


Code:
   <class name="ParticipantAddress" table="participant_addr">
      <composite-id>
         <key-property name="ownerNumber" column="owner_number" />
         <key-property name="participantId" column="participant_id" />
         <key-property name="addressType" column="address_type" />
      </composite-id>

      <property name="address1" column="address_1" />
      <property name="address2" column="address_2" />
      <property name="city" column="city" />
      <property name="state" column="state" />
      <property name="country" column="country" />
      <property name="zip" column="zip" />

   </class>






After removing the inverse="true", I'm seeing the following error on delete of address object.


21:54:26 DEBUG could not delete collection rows: [com.xxx.applications.dbobjects.Participant.addresses#26116] [update informix.participant_addr set partic
ipant_id=null where participant_id=? and owner_number=? and participant_id=? and address_type=?]
java.sql.SQLException: [BEA][Informix JDBC Driver][Informix]Primary key on table (participant_addr) has a field with a null key value.
at weblogic.jdbcspy.SpyLogger.sqlException(Unknown Source)
at weblogic.jdbcspy.SpyPreparedStatement.executeUpdate(Unknown Source)


What I really want to see is the follwoing query:


delete from participant_addr where participant_id=? and owner_number=? and address_type=?




Thanks for the quick response!


Last edited by a_shanmugam on Fri Apr 28, 2006 6:53 am, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 27, 2006 10:33 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
Your participant_addr table is very strange. What's the primary key? There isn't one, seeing as all columns can have nulls. Do you even have a unique constraint on owner_number/participant_id/address_type? This is bound to cause strangeness in the future. I strongly recommend changing your table to have a primary key. Make a new column for it, address_id or whatever.

To avoid the "update <table> set <key> = null" thing, change the <key> mapping in your set to include not-null="true".


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 27, 2006 11:49 pm 
Newbie

Joined: Mon Apr 24, 2006 2:01 pm
Posts: 13
The address table does not have a PK. This is a legacy DB.

Anyway the not-null thing does not work for me

Here is the new Mapping:


Code:
      <!-- collection mapping -->
      <set name="addresses" table="participant_addr" cascade="all,delete-orphan">
         <key column="participant_id" not-null="true" />
         <one-to-many class="ParticipantAddress" not-found="ignore" />
      </set>



Code:
   <class name="ParticipantAddress" table="participant_addr">
      <composite-id>
         <key-property name="ownerNumber" column="owner_number" />
         <key-property name="participantId" column="participant_id" insert="false" update="false" />
         <key-property name="addressType" column="address_type" />
      </composite-id>

      <property name="address1" column="address_1" />
      <property name="address2" column="address_2" />
      <property name="city" column="city" />
      <property name="state" column="state" />
      <property name="country" column="country" />
      <property name="zip" column="zip" />

   </class>


And getting the following error.

23:43:43 ERROR Error parsing XML: XML InputStream(665) Attribute "insert" must be declared for element type "key-property".
23:43:43 ERROR Error parsing XML: XML InputStream(665) Attribute "update" must be declared for element type "key-property".

Am I missing something ...?


Any workarounds in the mapping ...


THANKS!


Top
 Profile  
 
 Post subject:
PostPosted: Fri Apr 28, 2006 12:03 am 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
insert and update are not attributes that you can put on key-property. If you have a key that you can't insert/update, then you have an immutable table. In that case, you can remove the insert/update attributes and simply put mutable="false" in the <class> element.

_________________
Code tags are your friend. Know them and use them.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Apr 28, 2006 6:51 am 
Newbie

Joined: Mon Apr 24, 2006 2:01 pm
Posts: 13
Actually this is an updateable table. When I put the nut-null="true" in the collection mapping, it was complaining the following


org.hibernate.MappingException: Repeated column in mapping for entity: com.xxx.applications.dbobjects.ParticipantAddress column: participant_id (should be
mapped with insert="false" update="false")


Top
 Profile  
 
 Post subject:
PostPosted: Fri Apr 28, 2006 7:06 am 
Newbie

Joined: Mon Apr 24, 2006 2:01 pm
Posts: 13
Can you give the correct mapping for this relation.

Here is wat I want to acheive:


participant - --> address
has one-to-many relation. I want to cascade all operation on the participant to address.


participant PK column: participant_id
address unique columns (NO PK): participant_id and adress_type


THANKS


Top
 Profile  
 
 Post subject:
PostPosted: Sun Apr 30, 2006 5:37 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
I think you're almost there. I'm assuming that you want a bidirectional relationship, otherwise you wouldn't have gotten that repeated-column MappingException. Leave your <set> mapping like you posted before, and change the many-to-one in ParticipantAddress to use the formula="participantId" instead of column="participantId".

When you do this, you are committing to a parent-managed relationship. That is, you must not delete ParticipantAddress once you do this. You must instead remove them from the set that "owns" them. This will delete them just like you want.

_________________
Code tags are your friend. Know them and use them.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 15 posts ] 

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.