Greetings from a sunny Finland to everyone!
Hibernate version: 3.2.0 RC2
Mapping documents: Shortened to include only the affected classes:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.paroc.autosyst.device.domain" default-lazy="false">
<class name="Component" table="component">
<id name="UUID" type="com.paroc.ttp.common.hibernate.UUIDType">
<generator class="com.paroc.ttp.common.hibernate.UUIDGenerator"/>
</id>
<version name="version" column="version" type="integer" unsaved-value="null"/>
<property name="name" column="name" type="string" unique="true"/>
<property name="comments" column="comments" type="string"/>
<property name="componentVersion" column="componentVersion" type="string"/>
<property name="infoMissing" column="infoMissing" type="yes_no"/>
<property name="delivery" column="delivery" type="com.paroc.autosyst.device.domain.hibernate.ComponentDeliveryHT"/>
<one-to-one name="part" class="com.paroc.autosyst.device.domain.parts.Part" cascade="all"/>
<many-to-one name="parent" column="parent" class="Component"/>
<bag name="children" inverse="true" cascade="all" lazy="false" order-by="name">
<key column="parent"/>
<one-to-many class="Component"/>
</bag>
<bag name="IOComponents" table="compIOComponent" inverse="true" cascade="all-delete-orphan" lazy="false" order-by="description">
<key column="component" on-delete="cascade"/>
<one-to-many entity-name="compIOComponent"/>
</bag>
</class>
<class name="com.paroc.autosyst.location.domain.io.IOComponent" table="compIOComponent" entity-name="compIOComponent" abstract="true">
<id name="UUID" type="com.paroc.ttp.common.hibernate.UUIDType">
<generator class="com.paroc.ttp.common.hibernate.UUIDGenerator"/>
</id>
<version name="version" column="version" type="integer" unsaved-value="null"/>
<property name="description" column="description" type="string"/>
<many-to-one name="owner" column="component" class="com.paroc.autosyst.device.domain.Component"/>
<joined-subclass name="com.paroc.autosyst.location.domain.io.MeasuredValue" table="compIOMeasuredValue" entity-name="compMeasuredValue">
<key column="uuid"/>
<property name="reference" column="reference" type="string"/>
<one-to-one name="value" entity-name="compMeasuredValueValue" cascade="all" access="field" lazy="false"/>
</joined-subclass>
<joined-subclass name="com.paroc.autosyst.location.domain.io.Out" table="compIOOut" entity-name="compOut">
<key column="uuid"/>
<property name="reference" column="reference" type="string"/>
<property name="forceRef" column="forceRef" type="string"/>
<property name="forceVal" column="forceVal" type="double"/>
<one-to-one name="value" entity-name="compOutValue" cascade="all" access="field" lazy="false"/>
</joined-subclass>
</class>
<class name="com.paroc.autosyst.location.domain.io.signalhandling.Value" table="compIOMeasuredValueVal" entity-name="compMeasuredValueValue">
<id name="UUID" type="com.paroc.ttp.common.hibernate.UUIDType">
<generator class="foreign">
<param name="property">owner</param>
</generator>
</id>
<version name="version" column="version" type="integer" unsaved-value="null"/>
<property name="formatString" column="formatString" type="string" access="field"/>
<property name="max" column="valMax" type="string" access="field"/>
<property name="min" column="valMin" type="string" access="field"/>
<property name="unit" column="unit" type="string" access="field"/>
<property name="type" column="valType" type="com.paroc.autosyst.location.domain.io.signalhandling.hibernate.ValueTypeHT" access="field"/>
<one-to-one name="owner" entity-name="compMeasuredValue" constrained="true" access="field"/>
</class>
<class name="com.paroc.autosyst.location.domain.io.signalhandling.Value" table="compIOOutVal" entity-name="compOutValue">
<id name="UUID" type="com.paroc.ttp.common.hibernate.UUIDType">
<generator class="foreign">
<param name="property">owner</param>
</generator>
</id>
<version name="version" column="version" type="integer" unsaved-value="null"/>
<property name="formatString" column="formatString" type="string" access="field"/>
<property name="max" column="valMax" type="string" access="field"/>
<property name="min" column="valMin" type="string" access="field"/>
<property name="unit" column="unit" type="string" access="field"/>
<property name="type" column="valType" type="com.paroc.autosyst.location.domain.io.signalhandling.hibernate.ValueTypeHT" access="field"/>
<one-to-one name="owner" entity-name="compOut" constrained="true" access="field"/>
</class>
</hibernate-mapping>
Name and version of the database you are using: HSQLDB 1.8.0.4 / FirebirdSQL 1.5
The generated SQL (show_sql=true):Contains tables not included in the mapping above.
Code:
Hibernate: select iocomponen0_.component as component4_, iocomponen0_.UUID as UUID4_, iocomponen0_.UUID as UUID1_3_, iocomponen0_.version as version1_3_, iocomponen0_.description as descript3_1_3_, iocomponen0_.component as component1_3_, iocomponen0_1_.reference as reference2_3_, iocomponen0_2_.reference as reference3_3_, iocomponen0_2_.forceRef as forceRef3_3_, iocomponen0_2_.forceVal as forceVal3_3_, iocomponen0_3_.mode as mode4_3_, iocomponen0_3_.forceRef as forceRef4_3_, iocomponen0_3_.extRef as extRef4_3_, iocomponen0_3_.typical as typical4_3_, iocomponen0_3_.rampUp as rampUp4_3_, iocomponen0_3_.rampDown as rampDown4_3_, iocomponen0_3_.forceVal as forceVal4_3_, iocomponen0_4_.gain as gain5_3_, iocomponen0_4_.integrationTime as integrat3_5_3_, iocomponen0_4_.derivationTime as derivati4_5_3_, iocomponen0_5_.k as k6_3_, iocomponen0_5_.ratio as ratio6_3_, iocomponen0_6_.class as class7_3_, iocomponen0_6_.address as address7_3_, iocomponen0_7_.nameSuffix as nameSuffix8_3_, iocomponen0_10_.sMax as sMax11_3_, iocomponen0_10_.sMin as sMin11_3_, iocomponen0_10_.sType as sType11_3_, iocomponen0_11_.sFilter as sFilter12_3_, iocomponen0_11_.deadband as deadband12_3_, case when iocomponen0_8_.uuid is not null then 8 when iocomponen0_9_.uuid is not null then 9 when iocomponen0_11_.uuid is not null then 11 when iocomponen0_12_.uuid is not null then 12 when iocomponen0_7_.uuid is not null then 7 when iocomponen0_10_.uuid is not null then 10 when iocomponen0_1_.uuid is not null then 1 when iocomponen0_2_.uuid is not null then 2 when iocomponen0_3_.uuid is not null then 3 when iocomponen0_4_.uuid is not null then 4 when iocomponen0_5_.uuid is not null then 5 when iocomponen0_6_.uuid is not null then 6 when iocomponen0_.UUID is not null then 0 end as clazz_3_, compmeasur1_.UUID as UUID14_0_, compmeasur1_.version as version14_0_, compmeasur1_.formatString as formatSt3_14_0_, compmeasur1_.valMax as valMax14_0_, compmeasur1_.valMin as valMin14_0_, compmeasur1_.unit as unit14_0_, compmeasur1_.valType as valType14_0_, compoutval2_.UUID as UUID15_1_, compoutval2_.version as version15_1_, compoutval2_.formatString as formatSt3_15_1_, compoutval2_.valMax as valMax15_1_, compoutval2_.valMin as valMin15_1_, compoutval2_.unit as unit15_1_, compoutval2_.valType as valType15_1_, compiosign3_.UUID as UUID16_2_, compiosign3_.version as version16_2_, compiosign3_.formatString as formatSt3_16_2_, compiosign3_.valMax as valMax16_2_, compiosign3_.valMin as valMin16_2_, compiosign3_.unit as unit16_2_, compiosign3_.valType as valType16_2_ from compIOComponent iocomponen0_ left outer join compIOMeasuredValue iocomponen0_1_ on iocomponen0_.UUID=iocomponen0_1_.uuid left outer join compIOOut iocomponen0_2_ on iocomponen0_.UUID=iocomponen0_2_.uuid left outer join compIOSetPoint iocomponen0_3_ on iocomponen0_.UUID=iocomponen0_3_.uuid left outer join compIOPID iocomponen0_4_ on iocomponen0_.UUID=iocomponen0_4_.uuid left outer join compIORatio iocomponen0_5_ on iocomponen0_.UUID=iocomponen0_5_.uuid left outer join compIOSignal iocomponen0_6_ on iocomponen0_.UUID=iocomponen0_6_.uuid left outer join compIODigitalSignal iocomponen0_7_ on iocomponen0_.UUID=iocomponen0_7_.uuid left outer join compIODigitalInput iocomponen0_8_ on iocomponen0_.UUID=iocomponen0_8_.uuid left outer join compIODigitalOutput iocomponen0_9_ on iocomponen0_.UUID=iocomponen0_9_.uuid left outer join compIOAnalogSignal iocomponen0_10_ on iocomponen0_.UUID=iocomponen0_10_.uuid left outer join compIOAnalogInput iocomponen0_11_ on iocomponen0_.UUID=iocomponen0_11_.uuid left outer join compIOAnalogOutput iocomponen0_12_ on iocomponen0_.UUID=iocomponen0_12_.uuid left outer join compIOMeasuredValueVal compmeasur1_ on iocomponen0_.UUID=compmeasur1_.UUID left outer join compIOOutVal compoutval2_ on iocomponen0_.UUID=compoutval2_.UUID left outer join compIOSignalVal compiosign3_ on iocomponen0_.UUID=compiosign3_.UUID where iocomponen0_.component=? order by iocomponen0_.description
Hibernate: select children0_.parent as parent2_, children0_.UUID as UUID2_, children0_.UUID as UUID0_1_, children0_.version as version0_1_, children0_.name as name0_1_, children0_.comments as comments0_1_, children0_.componentVersion as componen5_0_1_, children0_.infoMissing as infoMiss6_0_1_, children0_.delivery as delivery0_1_, children0_.parent as parent0_1_, part1_.UUID as UUID17_0_, part1_.version as version17_0_, part1_.hardware as hardware17_0_, part1_1_.power as power18_0_, part1_1_.nomCurrent as nomCurrent18_0_, part1_2_.speed as speed19_0_, part1_2_.nomSpeed as nomSpeed19_0_, part1_3_.instrType as instrType20_0_, part1_3_.lmax as lmax20_0_, part1_3_.lmin as lmin20_0_, part1_3_.outputMax as outputMax20_0_, part1_3_.outputMin as outputMin20_0_, part1_3_.unit as unit20_0_, part1_3_.externalPower as external8_20_0_, part1_4_.outputType as outputType21_0_, part1_5_.outputType as outputType22_0_, part1_5_.medium as medium22_0_, part1_5_.ambientConditions as ambientC4_22_0_, part1_5_.physicalProperties as physical5_22_0_, case when part1_2_.uuid is not null then 2 when part1_4_.uuid is not null then 4 when part1_5_.uuid is not null then 5 when part1_1_.uuid is not null then 1 when part1_3_.uuid is not null then 3 when part1_.UUID is not null then 0 end as clazz_0_ from component children0_ left outer join superPart part1_ on children0_.UUID=part1_.UUID left outer join genericDevicePart part1_1_ on part1_.UUID=part1_1_.uuid left outer join motorPart part1_2_ on part1_.UUID=part1_2_.uuid left outer join abstractInstrumentPart part1_3_ on part1_.UUID=part1_3_.uuid left outer join transmitterPart part1_4_ on part1_.UUID=part1_4_.uuid left outer join sensorPart part1_5_ on part1_.UUID=part1_5_.uuid where children0_.parent=? order by children0_.name
Hibernate: select iocomponen0_.component as component4_, iocomponen0_.UUID as UUID4_, iocomponen0_.UUID as UUID1_3_, iocomponen0_.version as version1_3_, iocomponen0_.description as descript3_1_3_, iocomponen0_.component as component1_3_, iocomponen0_1_.reference as reference2_3_, iocomponen0_2_.reference as reference3_3_, iocomponen0_2_.forceRef as forceRef3_3_, iocomponen0_2_.forceVal as forceVal3_3_, iocomponen0_3_.mode as mode4_3_, iocomponen0_3_.forceRef as forceRef4_3_, iocomponen0_3_.extRef as extRef4_3_, iocomponen0_3_.typical as typical4_3_, iocomponen0_3_.rampUp as rampUp4_3_, iocomponen0_3_.rampDown as rampDown4_3_, iocomponen0_3_.forceVal as forceVal4_3_, iocomponen0_4_.gain as gain5_3_, iocomponen0_4_.integrationTime as integrat3_5_3_, iocomponen0_4_.derivationTime as derivati4_5_3_, iocomponen0_5_.k as k6_3_, iocomponen0_5_.ratio as ratio6_3_, iocomponen0_6_.class as class7_3_, iocomponen0_6_.address as address7_3_, iocomponen0_7_.nameSuffix as nameSuffix8_3_, iocomponen0_10_.sMax as sMax11_3_, iocomponen0_10_.sMin as sMin11_3_, iocomponen0_10_.sType as sType11_3_, iocomponen0_11_.sFilter as sFilter12_3_, iocomponen0_11_.deadband as deadband12_3_, case when iocomponen0_8_.uuid is not null then 8 when iocomponen0_9_.uuid is not null then 9 when iocomponen0_11_.uuid is not null then 11 when iocomponen0_12_.uuid is not null then 12 when iocomponen0_7_.uuid is not null then 7 when iocomponen0_10_.uuid is not null then 10 when iocomponen0_1_.uuid is not null then 1 when iocomponen0_2_.uuid is not null then 2 when iocomponen0_3_.uuid is not null then 3 when iocomponen0_4_.uuid is not null then 4 when iocomponen0_5_.uuid is not null then 5 when iocomponen0_6_.uuid is not null then 6 when iocomponen0_.UUID is not null then 0 end as clazz_3_, compmeasur1_.UUID as UUID14_0_, compmeasur1_.version as version14_0_, compmeasur1_.formatString as formatSt3_14_0_, compmeasur1_.valMax as valMax14_0_, compmeasur1_.valMin as valMin14_0_, compmeasur1_.unit as unit14_0_, compmeasur1_.valType as valType14_0_, compoutval2_.UUID as UUID15_1_, compoutval2_.version as version15_1_, compoutval2_.formatString as formatSt3_15_1_, compoutval2_.valMax as valMax15_1_, compoutval2_.valMin as valMin15_1_, compoutval2_.unit as unit15_1_, compoutval2_.valType as valType15_1_, compiosign3_.UUID as UUID16_2_, compiosign3_.version as version16_2_, compiosign3_.formatString as formatSt3_16_2_, compiosign3_.valMax as valMax16_2_, compiosign3_.valMin as valMin16_2_, compiosign3_.unit as unit16_2_, compiosign3_.valType as valType16_2_ from compIOComponent iocomponen0_ left outer join compIOMeasuredValue iocomponen0_1_ on iocomponen0_.UUID=iocomponen0_1_.uuid left outer join compIOOut iocomponen0_2_ on iocomponen0_.UUID=iocomponen0_2_.uuid left outer join compIOSetPoint iocomponen0_3_ on iocomponen0_.UUID=iocomponen0_3_.uuid left outer join compIOPID iocomponen0_4_ on iocomponen0_.UUID=iocomponen0_4_.uuid left outer join compIORatio iocomponen0_5_ on iocomponen0_.UUID=iocomponen0_5_.uuid left outer join compIOSignal iocomponen0_6_ on iocomponen0_.UUID=iocomponen0_6_.uuid left outer join compIODigitalSignal iocomponen0_7_ on iocomponen0_.UUID=iocomponen0_7_.uuid left outer join compIODigitalInput iocomponen0_8_ on iocomponen0_.UUID=iocomponen0_8_.uuid left outer join compIODigitalOutput iocomponen0_9_ on iocomponen0_.UUID=iocomponen0_9_.uuid left outer join compIOAnalogSignal iocomponen0_10_ on iocomponen0_.UUID=iocomponen0_10_.uuid left outer join compIOAnalogInput iocomponen0_11_ on iocomponen0_.UUID=iocomponen0_11_.uuid left outer join compIOAnalogOutput iocomponen0_12_ on iocomponen0_.UUID=iocomponen0_12_.uuid left outer join compIOMeasuredValueVal compmeasur1_ on iocomponen0_.UUID=compmeasur1_.UUID left outer join compIOOutVal compoutval2_ on iocomponen0_.UUID=compoutval2_.UUID left outer join compIOSignalVal compiosign3_ on iocomponen0_.UUID=compiosign3_.UUID where iocomponen0_.component=? order by iocomponen0_.description
Hibernate: select children0_.parent as parent2_, children0_.UUID as UUID2_, children0_.UUID as UUID0_1_, children0_.version as version0_1_, children0_.name as name0_1_, children0_.comments as comments0_1_, children0_.componentVersion as componen5_0_1_, children0_.infoMissing as infoMiss6_0_1_, children0_.delivery as delivery0_1_, children0_.parent as parent0_1_, part1_.UUID as UUID17_0_, part1_.version as version17_0_, part1_.hardware as hardware17_0_, part1_1_.power as power18_0_, part1_1_.nomCurrent as nomCurrent18_0_, part1_2_.speed as speed19_0_, part1_2_.nomSpeed as nomSpeed19_0_, part1_3_.instrType as instrType20_0_, part1_3_.lmax as lmax20_0_, part1_3_.lmin as lmin20_0_, part1_3_.outputMax as outputMax20_0_, part1_3_.outputMin as outputMin20_0_, part1_3_.unit as unit20_0_, part1_3_.externalPower as external8_20_0_, part1_4_.outputType as outputType21_0_, part1_5_.outputType as outputType22_0_, part1_5_.medium as medium22_0_, part1_5_.ambientConditions as ambientC4_22_0_, part1_5_.physicalProperties as physical5_22_0_, case when part1_2_.uuid is not null then 2 when part1_4_.uuid is not null then 4 when part1_5_.uuid is not null then 5 when part1_1_.uuid is not null then 1 when part1_3_.uuid is not null then 3 when part1_.UUID is not null then 0 end as clazz_0_ from component children0_ left outer join superPart part1_ on children0_.UUID=part1_.UUID left outer join genericDevicePart part1_1_ on part1_.UUID=part1_1_.uuid left outer join motorPart part1_2_ on part1_.UUID=part1_2_.uuid left outer join abstractInstrumentPart part1_3_ on part1_.UUID=part1_3_.uuid left outer join transmitterPart part1_4_ on part1_.UUID=part1_4_.uuid left outer join sensorPart part1_5_ on part1_.UUID=part1_5_.uuid where children0_.parent=? order by children0_.name
As you can see, I'm trying to map the Value-class twice, to the tables comIOMeasuredValueVal and compIOOutVal. They are both given different entity-names and are referenced by different classes (MeasuredValue and Out), using only their entity names.
If I create an object graph and save it, everything works OK, the values are stored in their respective tables, etc.
However, the problem occurs when I try to load the graph:
The value-properties of both the MeasuredValue and the Out classes are set to Null. However, if I remove the value reference from one of the classes - say MeasuredValue - the value-property of the Out-class is loaded correctly.
Thus it seems like every one-to-one association is ignored if the other end is a class that has been mapped more than once.
Perhaps I should mention that there are no error (or warning) messages what so ever in any error-logs, even when I run with debug-logging turned on.
Does anybody have any idea what this could be due to, and how to fix/work around the problem?
UPDATE: The problem also exists with Hibernate 3.1.3 and when replacing the one-to-one -mappings with fake foreign key mappings (many-to-one) as in ch 5 of the reference guide.
In addition, I've made some initial traces in the code and it looks like the Value objects are loaded OK and their owner properties updated accordingly (e.g Value -> MeasuredValue). However, the association is never made bidirectional (MeasuredValue -> Value). I even tried changing the access method to 'property' and rewriting the Value.setOwner() method to automatically invoke MeasuredValue.setOwner(this), but this did not work either. When the MeasuredValue is returned from loading, it still has its value-property set to null.
UPDATE #2: It looks like the MeasuredValue.value property is not updated as the association is found in StatefulPersistenceContext's nullAssociations-map. I'm trying to figure out how and why it got there.
UPDATE #3: Changing fetch to "select" seems to have solved the problem, but I'd still like to know exactly why this is working and "join" is not. Now unfortunately I don't know enough about Hibernate to figure this out on my own, perhaps somebody could so kind as to explain it to me or point me to some resources that do?
Thanks in advance,
-Petter-