-->
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.  [ 8 posts ] 
Author Message
 Post subject: composite keys - aargh!
PostPosted: Wed Dec 20, 2006 7:49 am 
Regular
Regular

Joined: Tue Oct 10, 2006 2:21 pm
Posts: 58
Need help with Hibernate? Read this first:
http://www.hibernate.org/ForumMailingli ... AskForHelp

Hibernate version: 3.05

Mapping documents:
<hibernate-mapping>
<class name="A" table="A">
<id name="a_id" column="a_id" length="30"/>
..
<bag name="bs"
inverse="true"
order-by="a_id,b_tn asc"
lazy="false">
<key column="a_id"/>
<one-to-many class="B" />
</bag>
</class>

<class name="B" table="B">

<composite-id>
<key-many-to-one name="a_id" class="A">
<column name="a_id" not-null="true" length="30"/>
</key-many-to-one>
<key-property name="b_tn">
<column name="b_tn" not-null="true" length="30"/>
</key-property>
</composite-id>
..
</class>

</hibernate-mapping>

Code between sessionFactory.openSession() and session.close():

Full stack trace of any exception that occurs:
Caused by: org.hibernate.PropertyAccessException: IllegalArgumentException occurred calling getter of com.att.up.prom.stac.data.EDndUserPreferences.userTn
at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:119)
at org.hibernate.tuple.AbstractTuplizer.getIdentifier(AbstractTuplizer.java:103)
at org.hibernate.persister.entity.BasicEntityPersister.getIdentifier(BasicEntityPersister.java:2944)
at org.hibernate.type.EntityType.getHashCode(EntityType.java:377)
at org.hibernate.type.ComponentType.getHashCode(ComponentType.java:162)
at org.hibernate.engine.EntityKey.getHashCode(EntityKey.java:68)
at org.hibernate.engine.EntityKey.<init>(EntityKey.java:41)
at org.hibernate.engine.PersistenceContext.getDatabaseSnapshot(PersistenceContext.java:296)
at org.hibernate.engine.ForeignKeys.isTransient(ForeignKeys.java:189)
at org.hibernate.event.def.AbstractSaveEventListener.getEntityState(AbstractSaveEventListener.java:409)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:82)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:69)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:468)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:463)
at com.whatever.Dao.updateA(Dao.java:130)
... 19 more
Caused by: java.lang.IllegalArgumentException: object is not an instance of declaring class
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:85)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:58)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:60)
at java.lang.reflect.Method.invoke(Method.java:391)
at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:105)
... 33 more




Name and version of the database you are using:Oracle 9



I have inherited a legacy schema (not that old but I have no control over it, God bless outsourcing).

In a nutshell, the main table has a program-assigned primary key (non-synthetic) and the secondary table has a composite primary key consisting of a foreign key field referencing the main table's primary key and another non-synthetic key field in the secondary table.

It is defined as follows:

CREATE TABLE "A"
( "A_ID" VARCHAR2(30 BYTE) NOT NULL ENABLE,
PRIMARY KEY ("A_ID") ENABLE
) ;

CREATE TABLE "B"
(
"A_ID" VARCHAR2(30 BYTE) NOT NULL ENABLE,
"B_TN" VARCHAR2(30 BYTE) NOT NULL ENABLE,
...
PRIMARY KEY ("A_ID", "B_TN") ENABLE,
CONSTRAINT "FK3D31C5A96D99FB8" FOREIGN KEY ("A_ID")
REFERENCES "A" ("A_ID") ENABLE
) ;

POJOs:


public class B
implements Comparable, Serializable
{
private String b_tn;
private String a_id;
private String blockedName;
public String getB_tn() {
return b_tn;
}
public void setB_tn(String b_tn) {
this.b_tn = b_tn;
}
public String getA_id() {
return a_id;
}
public void setA_id(String a_id) {
this.a_id = a_id;
}
public int compareTo(Object o) {
B that = (B) o;
int result = this.a_id.compareTo(that.a_id);
if (result == 0) {
result = this.b_tn.compareTo(that.b_tn);
}
return result;
}
public boolean equals(Object obj) {
if (!(obj instanceof B)) {
return false;
}
B that = (B) obj;
if (!this.a_id.equals(that.a_id)) {
return false;
}
return this.b_tn.equals(that.b_tn);
}
public int hashCode() {
return 37 * this.a_id.hashCode()
+ this.b_tn.hashCode();
}

}

public class A
implements Serializable
{
private String a_id;
private List bs;
...

public String getA_id() {
return a_id;
}
public void setA_id(String a_id) {
this.a_id = a_id;
}
public List getBs() {
return bs;
}
public void setBs(List bs) {
this.bs = bs;
}

}



I know this is not best practice but I have no control here. I thought it would be simple to map this collection, but it is killing me.

Everything looks good until I try to add a B to A.bs and persist it. Then I get the above exception. I've tried everything. I simply don't understand why this InvalidArgumentException is being thrown when attempting to invoke a simple getter through reflection. My initial thought was to cascade everything but then I saw in the DTD that <key-many-to-one> should never be cascaded. Didn't matter, failed either way.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 20, 2006 8:20 am 
Regular
Regular

Joined: Thu Aug 17, 2006 4:50 am
Posts: 55
Location: Mallorca
It looks like you are mapping the composite-id with the a_id property being an entity ...
Code:
<class name="B" table="B">

   <composite-id>
       <key-many-to-one name="a_id" class="A">
          <column name="a_id" not-null="true" length="30"/>
       </key-many-to-one>
       <key-property name="b_tn">
            <column name="b_tn" not-null="true" length="30"/>
        </key-property>
    </composite-id>
..
</class>


... but in the code, the a_id property is a String ( A entity primary key)

Code:
public class B
implements Comparable, Serializable
{
private String b_tn;
private String a_id;
...


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 20, 2006 8:50 am 
Regular
Regular

Joined: Tue Oct 10, 2006 2:21 pm
Posts: 58
Quote:
It looks like you are mapping the composite-id with the a_id property being an entity ...
... but in the code, the a_id property is a String ( A entity primary key)


Okay, thanks, that makes sense.

But how to fix? If I remove class="A", I will be all right? But how then do I tell Hibernate about the foreign key mapping to A on a_id? That was my original reason for mapping that way.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 20, 2006 8:52 am 
Regular
Regular

Joined: Thu Aug 17, 2006 4:50 am
Posts: 55
Location: Mallorca
change the POJO:


Code:
public class B
implements Comparable, Serializable
{
private String b_tn;
private A a;
...



and the mapping

Code:
<composite-id>
       <key-many-to-one name="a" class="A">
          <column name="a_id" not-null="true" length="30"/>
       </key-many-to-one>


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 20, 2006 9:19 am 
Regular
Regular

Joined: Tue Oct 10, 2006 2:21 pm
Posts: 58
There is no need for B to have a reference back to A. The association is from A to B. A has Bs. B doesn't need to know about A, but uses its ID as a mechanism to show that it is owned by A.

Of course that might mean that inverse="true" isn't needed. However removing it doesn't help.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 20, 2006 9:22 am 
Regular
Regular

Joined: Thu Aug 17, 2006 4:50 am
Posts: 55
Location: Mallorca
then, consider b.a_id just another property ...

Code:
<class name="B" table="B">

   <composite-id>
       <key-property name="a_id" >
          <column name="a_id" not-null="true" length="30"/>
       </key-many-to-one>
       <key-property name="b_tn">
            <column name="b_tn" not-null="true" length="30"/>
        </key-property>
    </composite-id>
..
</class>



Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 20, 2006 10:39 am 
Regular
Regular

Joined: Tue Oct 10, 2006 2:21 pm
Posts: 58
Yeah, that's the ticket. I had thought I had to use <key-many-to-one> in B in order to generate the foreign key relationship but that is already taken care of by the <bag><one-to-many> mapping in A to B.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 20, 2006 11:55 am 
Regular
Regular

Joined: Tue Oct 10, 2006 2:21 pm
Posts: 58
It would be good if Hibernate team could beef up the documentation of <key-many-to-one> and <key-property>. I realize that these are semi-deprecated ideas that you don't want to encourage, but both of these tags have listed attributes in the DTD that are neither documented nor have examples provided for them in the manual or in the test source code that the manual recommends as a source for examples.

The above is based on 3.0.5 distribution. I haven't checked if more recent releases ameliorate this.


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