Hi,
First, I'm a somewhat experienced OJB user, attempting to learn Hibernate for evaluation purposes. As such, I am starting with a data model that works with OJB already, and am attempting to get similar functionality within Hibernate (using the DAO pattern).
My problem seems to be with composite id's. I've searched the documentation numerous times, and also searched these forums, but haven't found anything that specifically relates to my problem (although I could have missed something). I'm unable to get an "anonymous" <composite-id> relationship using <key-many-to-one> with bi-directional references between two mappings.
I'm trying to map an Address to Country and State, where State has a Country and Country contains States. Whether or not this is a good model is not debatable (altho it's obviously not ;) )
Even when I remove the <bag> of states from Country (and thus break the bi-directional mapping), the external reference from Address still fails (even though I override .equals(Object obj)) with this error:
Code:
ObjectNotFoundException: No row with the given identifier exists: test.common.data.model.State@6567, of class: test.common.data.model.State
Here is a snippet my hibernate mapping XML file:
Code:
<!--+
| Address
+-->
<class name="test.common.data.model.Address" schema="TEST" table="ADDRESS">
<id column="ADDRESS_ID" name="addressId" type="integer">
<generator class="sequence"/>
</id>
<property column="STREET_1" length="100" name="street1" type="string"/>
<property column="CITY" length="100" name="city" type="string"/>
<many-to-one name="state" class="test.common.data.model.State">
<column name="COUNTRY_CODE"/>
<column name="STATE_CODE"/>
</many-to-one>
<many-to-one name="country" class="test.common.data.model.Country" column="COUNTRY_CODE" insert="false" update="false" /> <!-- insert/update false is required because COUNTRY_CODE defined in State above -->
<property column="POSTAL_CODE" length="10" name="postalCode" type="string"/>
</class>
<!--+
| Country
+-->
<class name="test.common.data.model.Country" schema="TEST" table="COUNTRY">
<id column="COUNTRY_CODE" length="2" name="countryCode" type="string"> <!-- ISO-3166 code -->
<generator class="assigned"/>
</id>
<property column="DESCRIPTION" length="200" name="name" type="string"/>
<bag name="states" table="STATE" lazy="true">
<key>
<column name="COUNTRY_CODE"/>
<column name="STATE_CODE"/>
</key>
<one-to-many class="test.common.data.model.State"/>
</bag>
</class>
<!--+
| State
+-->
<class name="test.common.data.model.State" schema="TEST" table="STATE">
<composite-id>
<key-many-to-one name="country" class="test.common.data.model.Country" column="COUNTRY_CODE"/>
<key-property name="stateCode" column="STATE_CODE"/> <!-- ISO-3166-2 code -->
</composite-id>
<property column="DESCRIPTION" length="100" name="name" type="string"/>
</class>
And here are the associated tables:
Code:
create table ADDRESS
(
ADDRESS_ID NUMBER(10) not null,
STREET_1 VARCHAR2(100),
CITY VARCHAR2(100),
STATE_CODE CHAR(4),
COUNTRY_CODE CHAR(2),
POSTAL_CODE VARCHAR2(10)
);
alter table ADDRESS
add constraint PK_ADDRESS primary key (ADDRESS_ID);
alter table ADDRESS
add constraint ADDRESS_FK_1 foreign key (COUNTRY_CODE);
alter table ADDRESS
add constraint ADDRESS_FK_2 foreign key (COUNTRY_CODE,STATE_CODE)
create table COUNTRY
(
COUNTRY_CODE CHAR(2) not null,
DESCRIPTION VARCHAR2(200)
);
alter table COUNTRY
add constraint COUNTRY_PK primary key (COUNTRY_CODE);
create table STATE
(
COUNTRY_CODE CHAR(2) not null,
STATE_CODE CHAR(4) not null,
DESCRIPTION VARCHAR2(100)
);
alter table STATE
add constraint PK_STATE primary key (COUNTRY_CODE,STATE_CODE);
It's relatively easy to map this in OJB using <reference-descriptor> and <inverse-foreign-key>. But I'm struggling mightily with the correct Hibernate syntax.
My java code is POJO's with setters and getters, with the exception of State, which implements Serializable and overrides .equals(Object obj) and hashcode(). Unfortunately, overriding .hashcode() breaks OJB. I can post this code if necessary.
Is it even possible to correctly model this relationship this way in hibernate? I'd rather not introduce a new class to represent the PK of STATE (as this could have serious OJB implications), but I realize I may have to. Also, should I look into <compsite-element> for help? That's the one area I haven't explored thoroughly. And finally, what explicitly does overriding .equals(Object obj) and .hashcode() do in Hibernate? For the caching mechanisms? Or something more "important"?
Thanks in advance for your help! And let me know if I need to post anything else.
Oh, and one more thing before I forget it -- if possible, I would suggest explicitly checking for "Serializable" in net.sf.hibernate.loader.Loader.getKeyFromResultSet(Loader.java:286) and throwing a more meaningful exception than "ClassCastException". I know the docs state that you must implement Serializable, but there is very little example code for "anonymous" <composite-id> usage, and as such, I missed it the first time. Just my 2 cents.