-->
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.  [ 12 posts ] 
Author Message
 Post subject: joined subclass one-to-many mapping with composite key
PostPosted: Thu Jan 29, 2004 4:32 pm 
Beginner
Beginner

Joined: Wed Jan 28, 2004 3:42 pm
Posts: 36
Hi,

I'm running into the following problem which has me somewhat baffled being new to Hibernate. I'll try to keep this short, I have the following situation:

DocumentHeader
| 1
|
| 1
CommitmentDocument
| 1
|
| *
CommitmentLineItem

Looks innocent enough eh? CommitmentDocument extends DocumentHeader, so from the application perspective only a CommitmentDocument object exists, however it's persisted to two distinct tables, doc_header_t and commitment_doc_t. In effect a one to one mapping exists between the two, using a shared primary key (fdocNbr). CommitmentDocument in turn has a collection of line items (List of CommitmentLineItem). The CommitmentDocument object shares the same primary key (fdocNbr) with the CommitmentLineItems, CommitmentLineItems also has a sequence within the scope of the document number (fdocNbr) and together with the document number this sequence makes out the primary key (composite) for the CommitmentLineItem.

The mapping looks something like this (abbreviated):

<class name="DocumentHeader" table="DOC_HEADER_T">
<id name="fdocNbr" type="string" unsaved-value="null">
<column name="FDOC_NBR" not-null="true" length="36"/>
<generator class="PaddedSequenceGenerator">
<param name="sequence">document_number</param>
<param name="total_width">5</param>
</generator>
</id>

<joined-subclass name="CommitmentDocument" table="COMMITMENT_DOC_T">
<key column="FDOC_NBR">
</key>

</joined-subclass>
<bag
name="lineItems"
inverse="true"
lazy="false"
order-by="FDOC_LINE_NBR"
cascade="all">

<key column="FDOC_NBR"/>
<one-to-many class="CommitmentLineItem"/>
</bag>

</class>

<class
name="CommitmentLineItem"
table="COMMITMENT_LINE_T"
>

<composite-id name="comp_id" class="CommitmentLineItemPK">
<key-many-to-one
name="fdocNbr"
class="CommitmentDocument"
column="FDOC_NBR"
/>
<key-property
name="fdocLineNbr"
column="FDOC_LINE_NBR"
type="java.lang.Integer"
length="7"
/>
</composite-id>

</class>

Now to test this I do the following, create a new DommitmentDocument, save (session.save) it (to get the doc number back), the I load it (session.load), then I create a new CommitmentLineItem and CommitmentLineItemPK objects and add them to the loaded document, and then try to save the whole thing again:

String newDocNumber = pcd.saveDocument(cd);
CommitmentDocument cd2 = pcd.loadDocument(newDocNumber);
pcd.printDocument(cd2);
item1.setDocument(cd2);
cd2.getLineItems().add(item1);
pcd.saveDocument(cd2);

It works until I try to save the document again with the lineItems, I get the following exception:

[java] IllegalArgumentException occurred calling getter of com.imi.hsos.document.fcom.persistence.DocumentHeader.fdocNbr
[java] net.sf.hibernate.PropertyAccessException: IllegalArgumentException occurred calling getter of com.imi.hsos.document.fcom.persistence.DocumentHeader.fdocNbr
[java] at net.sf.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:110)
.
.
.
.
[java] Caused by: java.lang.IllegalArgumentException: object is not an instance of declaring class
[java] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[java] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

I guess my question is two fold, does the mapping look alright and any ideas/pointers on why this exception gets thrown ? The model is driven from the ERD basically, it's fairly fixed and I don't have much chance of having it changed.

Many thanks!
Peter


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 29, 2004 5:43 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
I don't see anything immediately wrong with the mapping. Put the Hibernate source in your classpath and add a breakpoint at the line that throws the excpetion. That is usually the quickest way to track down these kinds of things.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 29, 2004 5:44 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Actually, don't you intend the <bag> mapping to be inside the <joined-subclass> element?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 29, 2004 6:20 pm 
Beginner
Beginner

Joined: Wed Jan 28, 2004 3:42 pm
Posts: 36
Thank you for the reply Gavin, you are of course correct, with my wild copy and paste I somehow managed with the bag outside the joined subclass, in my mapping file it is indeed inside the joined subclass as you suspected.

I will try your other suggestion and see what I can find.

Thanks again,
Peter


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 29, 2004 10:25 pm 
Beginner
Beginner

Joined: Wed Jan 28, 2004 3:42 pm
Posts: 36
Hi,

I've narrowed down the exception to:

net/sf/hibernate/impl/SessionImpl.java:flushEverything()

new Printer(factory).toString( entitiesByKey.values().iterator() );

and in Printer.toString():

log.debug( toString( iter.next() ) );

It starts recursing, at some point it calls ClassMetadata.getIdentiierType().toString() which calls EntityType.toString() ... ok eventually it gets to ComponentType.toString(Object,SessionFactoryImplementor) which calls getPropertyValues() on my CommitmentLineItemPK object. Now it calls on each of these properties toString(), which eventually ends up using reflection to call getFdocNbr() (which returns the shared primary key in this hierarchy) on this first property (which is "00074" - iow, this property is the fdocNbr, not an object!) Then of course it throws the exception seen, the class is indeed not an instance of the expected class. I'm not sure why this method is not called on the PK object instead of the contents of the PK object ?

Any enlightenment would be appreciated!

Thanks,
Peter


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 29, 2004 10:47 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Ummmm. What happens if you disable logging? Printer is only called if logging is enabled....


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 29, 2004 10:54 pm 
Beginner
Beginner

Joined: Wed Jan 28, 2004 3:42 pm
Posts: 36
Yes, I did that first thing :) I ran into a mapping exception so I decided to go back to debug and see what happens.


[java] 18:50:43,020 ERROR SessionImpl:2269 - Could not synchronize database state with session
[java] net.sf.hibernate.MappingException: No persister for: java.lang.String
[java] at net.sf.hibernate.type.ManyToOneType.nullSafeSet(ManyToOneType.java:46)
[java] at net.sf.hibernate.type.ComponentType.nullSafeSet(ComponentType.java:154)
[java] at net.sf.hibernate.impl.SessionFactoryImpl.getPersister(SessionFactoryImpl.java:344)
[java] at net.sf.hibernate.impl.SessionImpl.getClassPersister(SessionImpl.java:2574)
[java] at net.sf.hibernate.persister.EntityPersister.dehydrate(EntityPersister.java:400)
[java] at net.sf.hibernate.impl.SessionImpl.getPersister(SessionImpl.java:2581)
[java] at net.sf.hibernate.persister.EntityPersister.update(EntityPersister.java:651)
[java] at net.sf.hibernate.persister.EntityPersister.update(EntityPersister.java:625)
[java] at net.sf.hibernate.impl.SessionImpl.getEntityIdentifierIfNotUnsaved(SessionImpl.java:2643)
[java] at net.sf.hibernate.type.EntityType.getIdentifier(EntityType.java:66)
[java] at net.sf.hibernate.impl.ScheduledUpdate.execute(ScheduledUpdate.java:52)
[java] at net.sf.hibernate.impl.SessionImpl.executeAll(SessionImpl.java:2308)
[java] at net.sf.hibernate.type.ManyToOneType.nullSafeSet(ManyToOneType.java:46)
[java] at net.sf.hibernate.type.ComponentType.nullSafeSet(ComponentType.java:154)
[java] at net.sf.hibernate.impl.SessionImpl.execute(SessionImpl.java:2262)
[java] at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2187)
.
.
.


A really ignorant question if I may, when having debug enabled the stacktrace for the IllegalArgumentException is indispersed with the debug output, which I guess would indicate different threads but in the debugger I only see one non system thread?

Thanks much,
Peter


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 29, 2004 10:56 pm 
Beginner
Beginner

Joined: Wed Jan 28, 2004 3:42 pm
Posts: 36
Er, just to confirm, I gather you mean disable DEBUG logging, which is what I did :)


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 30, 2004 1:20 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
Does this fits to you ?
http://forum.hibernate.org/viewtopic.php?t=927332&highlight=

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 30, 2004 2:47 pm 
Beginner
Beginner

Joined: Wed Jan 28, 2004 3:42 pm
Posts: 36
Thanks for the feedback Emmanual, I don't think this case applies to me, I only add one item to the collection:

CommitmentDocument cd2 = pcd.loadDocument(newDocNumber);
pcd.printDocument(cd2);
item1.setDocument(cd2);
cd2.getLineItems().add(item1);
System.out.println("We've added the new line item");
pcd.printDocument(cd2);
pcd.saveDocument(cd2);

We do run into the same problems though, problems in Printer...

Do you have any suggestions on how to track down the problem that still exists when I disabled DEBUG logging?

Thanks!
Peter


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 30, 2004 4:51 pm 
Beginner
Beginner

Joined: Wed Jan 28, 2004 3:42 pm
Posts: 36
I have another question here. Currently I'm saving the CommitmentDocument first to get a fdocNbr and then load it, create the new line item, add it, and then save the whole thing. I do this because fdocNbr is part of the line item's composite primary key.

I tried to create the whole object first but not assigned the fdocNbr in the line item's composite key and saving the object, it failed though, would this not be possible?

Thanks
Peter


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 30, 2004 11:55 pm 
Beginner
Beginner

Joined: Wed Jan 28, 2004 3:42 pm
Posts: 36
I looked further into the MappingException: No persister for: java.lang.String

The problem starts when ComponentType.nullSafeSet receives the PK object and then starts iterating through the subvalues (a String (fk) and an Integer). This then calls ManyToOneType.nullSafeSet on the first value. This method determines it's dealing with a String and then calls EntityType.getIdentifierOrUniqueKeyType() and so on, basically trying to find a ClassPersister for String, which fails.


Now, simply changing the key-many-to-one to a key-property solves the problem and the objects gets persisted but of course there's no relationships.

Any ideas?
Thanks,
Peter


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 12 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.