Hibernate Books

All times are UTC - 5 hours [ DST ]



Post new topic Reply to topic  [ 13 posts ] 
Author Message
 Post subject: key-many-to-one class must be serializable?
PostPosted: Thu May 18, 2006 10:05 am 
Newbie

Joined: Thu May 18, 2006 10:00 am
Posts: 12
Hi all,

I'm trying to determine why entities used as key-many-to-one in a composite-id mapping need to be serializable. I've searched thru the docs to no avail, they merely state it has to be that way. I would like to understand the reason before blindly implementing serializable on my entities.

Thanks in advance for your help!


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 18, 2006 11:11 am 
Expert
Expert

Joined: Tue Apr 25, 2006 12:04 pm
Posts: 260
I still am not sure why the class for composite-id must be serializable. But implement equals() and hashCode() methods so that your dont face some problems( possible ). This was mandatory in version 2.x and optional in 3.x for some reason.

Will give an example where implementing those methods can be helpful.

Always want to check, if a child object is existing in lazy collection before "adding/deleting" from parent. So when a user submits a request to "add/delete" few of the children, I get only primary key fields with which I construct object with primary key fields set. With this object I want to check if any persistent entity is existing in the parent collection of child objects. Without overriding equals() and hashCode(), I was not getting consistent results when I was checking for child entity availability in lazy collection. Even


Code:
Parent parent = (Parent) session.get( Parent.class, parentPrimaryKey );
Child addChild1 = new Child();
addChild1.setPrimaryKeyFields();

Child addChild2 = new Child();
addChild2.setPrimaryKeyFields();

Child deleteChild1 = new Child();
deleteChild1.setPrimaryKeyFields();

if ( ! parent.getChildCollection().contains( addChild1 ) ) {
   parent.getChildCollection().add( addChild1 );
}

if ( ! parent.getChildCollection().contains( addChild2 ) ) {
   parent.getChildCollection().add( addChild2 );
}

if ( parent.getChildCollection().contains( addChild1 ) ) {
   parent.getChildCollection().remove( deleteChild1 );
}

// call to modify some of parents attributes
modifyNonPrimarykeyFieldsOfParent( parent );

session.saveOrUpdate( parent );


Without equals() and hashCode() I was getting
org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session:

If anyone has an idea for better solution, please let me know. For now, I am implementing equals() and hashCode() to make it work.


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 18, 2006 3:37 pm 
Newbie

Joined: Thu May 18, 2006 10:00 am
Posts: 12
Can someone explain why identifiers must be serializable?


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 18, 2006 5:06 pm 
Expert
Expert

Joined: Tue Apr 25, 2006 12:04 pm
Posts: 260
I want to make correction in your question. Its the class that is mentioned in <composite-id> needs to implement Serializable interface and not the class in <key-many-to-one>. Excuse me if I overstate this one because the statement is misleading in your question.

Quote:
why entities used as key-many-to-one in a composite-id mapping need to be serializable


Let me come around, Hibernate expects persistable information(to columns) needs to be of Serializable.

If you go through the sources, the method signatures expect Serializable type when it is expecting anything unique that identifies a row in the database i.e. a primary key. So to enforce the restriction, during configuration time hibernate checks if the <composite-id> class is Serializable, otherwise an exception is thrown.


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 18, 2006 5:35 pm 
Newbie

Joined: Thu May 18, 2006 10:00 am
Posts: 12
No, I believe I stated it correctly.

Here is an example:
Code:
       
<composite-id>
  <key-many-to-one name="entityA" class="entityA" column="entityA_id"/>
  <key-many-to-one name="entityB" class="entityB" column="entityB_id"/>      
</composite-id>


entityA and entityB are hibernate managed entities. This mapping basically tells hibernate to get the composite-id values from the other entities. My question is, why do the entities need to be serializable? The identifiers of the other entities are already serializable.

Am I missing something here? thanks


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 18, 2006 5:38 pm 
Expert
Expert

Joined: Tue Apr 25, 2006 12:04 pm
Posts: 260
Classes entityA and entityB doesnt need to be serializable. Did you got any exception with such mapping?


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 18, 2006 7:01 pm 
Newbie

Joined: Thu May 18, 2006 10:00 am
Posts: 12
yes, here it is:

Code:
SEVERE: Error initializing Hibernate.
org.hibernate.MappingException: composite-id class must implement Serializable: com.XXX.EntityA       
at org.hibernate.mapping.RootClass.checkCompositeIdentifier(RootClass.java:220)
at org.hibernate.mapping.RootClass.validate(RootClass.java:201)
at org.hibernate.cfg.Configuration.validate(Configuration.java:984)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1169)


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 18, 2006 9:15 pm 
Expert
Expert

Joined: Tue Apr 25, 2006 12:04 pm
Posts: 260
Code:
<composite-id name="compositePK" class="MyCompositePK">
  <key-many-to-one name="entityA" class="entityA" column="entityA_id"/>
  <key-many-to-one name="entityB" class="entityB" column="entityB_id"/>       
</composite-id>


public class MyCompositePK implements Serializable {
   private ClassEntityA entityA;
   private ClassEntityB entityB;

   // setters, getters, equals, hashCode
}

public class MyPersistent {
   private MyCompositePK  compositePK;
   // other properties;
}

public class ClassEntityA {
   // properties
   // need not implement Serializable
}

public class ClassEntityB {
   // properties
   // need not implement Serializable
}


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 19, 2006 9:45 am 
Newbie

Joined: Thu May 18, 2006 10:00 am
Posts: 12
I see what you are saying, but I am trying to avoid a class to encapsulate the key. I am not using anything like "MyCompositePK". My mapping works just fine, except that I have to implement serializable on my entities.


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 19, 2006 9:53 am 
Expert
Expert

Joined: Tue Apr 25, 2006 12:04 pm
Posts: 260
other approach would be

Code:
<composite-id>
   <key-property name="entityA" class="entityA" column="entityA_id" />
   <key-property name="entityB" class="entityB" column="entityB_id" />
</composite-id>
<many-to-one name="entityAObject" class="entityA" column="entityA_id" insert="false" update="false"/>
<many-to-one name="entityBObject" class="entityB" column="entityB_id" insert="false" update="false"/>       


Just curious, is the class which has composite is Serializable?


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 19, 2006 10:23 am 
Beginner
Beginner

Joined: Thu Mar 18, 2004 8:11 am
Posts: 38
Location: Italy
crook wrote:
I see what you are saying, but I am trying to avoid a class to encapsulate the key. I am not using anything like "MyCompositePK". My mapping works just fine, except that I have to implement serializable on my entities.


You don't have to. You may just stuff your hashCode and equals in the entity class having he composite identifier.

Like:

Code:
<class name="YourOwnEntity" ... >
<composite-id>
   <key-many-to-one name="entityA" class="entityA" column="entityA_id"/>
   <key-many-to-one name="entityB" class="entityB" column="entityB_id"/>
</composite-id>

...

</class>

_________________
Giampaolo Tomassoni
Italy


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 19, 2006 11:14 am 
Newbie

Joined: Thu May 18, 2006 10:00 am
Posts: 12
Looks like your right, it is only the class that has the composite-id needs to be serializable. Classes mapped w/ a composite-id are their own identifiers and thus must be serializable. Thanks guys.

So this brings me to the question, why is it that identifiers need to be serializable? At what point are they serialized/de-serialized by hibernate?


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 19, 2006 12:55 pm 
Beginner
Beginner

Joined: Thu Mar 18, 2004 8:11 am
Posts: 38
Location: Italy
jdbc data types are serializable. Remoting (ejb and the like) uses serialization to exchange data. Thereby, every data type in hibernate is serializable. A composite key may be regarded as a data type itself: after all, it isn't that much different from a key based on a simpler type.

Also note that every hibernate entity is made, soon (by you) or later (by the hibernate wrapping class), serializable: it must be remotable.

The equals and hashCode functions of your composite must be consistent with the serializable portion of the composite itself. This means that they must cope with every non-transient (in a wider meaning then just the 'transient' java keyword) property of the composite.

... I guess.

_________________
Giampaolo Tomassoni
Italy


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 13 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.