Note that there are some explanatory texts on larger screens.

plurals
  1. POWhy is my multi-level inheritance mapping not working as I would expect it to?
    text
    copied!<p>I have the following entity mappings:</p> <pre><code>// user.cfc component persistent="true" table="user" discriminatorColumn="userTypeID" { property name="id" column="userID" fieldtype="id" generator="identity"; property name="type" fieldtype="many-to-one" cfc="userType" fkcolumn="userTypeID"; } // admin.cfc component extends="user" persistent="true" table="admin" joincolumn="userID" discriminatorValue="3" { property name="id" column="adminID" fieldtype="id" generator="identity"; } // employee.cfc component extends="user" persistent="true" table="employee" joincolumn="userID" discriminatorValue="0" { property name="id" column="employeeID" fieldtype="id" generator="identity"; } // manager.cfc component extends="employee" persistent="true" table="manager" joincolumn="employeeID" discriminatorValue="1" { property name="id" column="managerID" fieldtype="id" generator="identity"; } // intern.cfc component extends="employee" persistent="true" table="intern" joincolumn="employeeID" discriminatorValue="2" { property name="id" column="internID" fieldtype="id" generator="identity"; } </code></pre> <p>Per Henry's suggestion, here are the generated hbmxml files:</p> <pre><code>&lt;!-- user.hbmxml --&gt; &lt;!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"&gt; &lt;hibernate-mapping&gt; &lt;class entity-name="user" lazy="true" name="cfc:user" table="user"&gt; &lt;id name="ID" type="int"&gt; &lt;column name="userID"/&gt; &lt;generator class="identity"/&gt; &lt;/id&gt; &lt;discriminator column="userTypeID"/&gt; &lt;many-to-one class="cfc:userType" column="userTypeID" insert="false" name="type" update="false"/&gt; &lt;/class&gt; &lt;/hibernate-mapping&gt; &lt;!-- admin.hbmxml --&gt; &lt;!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"&gt; &lt;hibernate-mapping&gt; &lt;subclass discriminator-value="3" entity-name="admin" extends="cfc:user" lazy="true" name="cfc:admin"&gt; &lt;join table="admin"&gt; &lt;key column="userID"/&gt; &lt;/join&gt; &lt;/subclass&gt; &lt;/hibernate-mapping&gt; &lt;!-- employee.hbmxml --&gt; &lt;!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"&gt; &lt;hibernate-mapping&gt; &lt;subclass discriminator-value="0" entity-name="employee" extends="cfc:user" lazy="true" name="cfc:employee"&gt; &lt;join table="employee"&gt; &lt;key column="userID"/&gt; &lt;/join&gt; &lt;/subclass&gt; &lt;/hibernate-mapping&gt; &lt;!-- manager.hbmxml --&gt; &lt;!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"&gt; &lt;hibernate-mapping&gt; &lt;subclass discriminator-value="1" entity-name="manager" extends="cfc:employee" lazy="true" name="cfc:manager"&gt; &lt;join table="manager"&gt; &lt;key column="employeeID"/&gt; &lt;/join&gt; &lt;/subclass&gt; &lt;/hibernate-mapping&gt; &lt;!-- intern.hbmxml --&gt; &lt;!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"&gt; &lt;hibernate-mapping&gt; &lt;subclass discriminator-value="2" entity-name="intern" extends="cfc:employee" lazy="true" name="cfc:intern"&gt; &lt;join table="intern"&gt; &lt;key column="employeeID"/&gt; &lt;/join&gt; &lt;/subclass&gt; &lt;/hibernate-mapping&gt; </code></pre> <p>If it's not clear from the mappings, the relationships are as follows:</p> <pre><code>user |- admin |- employee |- manager |- intern </code></pre> <p>The intention is for the <code>type</code> property on the <code>user</code> entity to be populated by the discriminator value of the <code>manager</code> and <code>intern</code> entities. There is code in <code>employee</code>'s constructor that keeps it from being instantiated directly, so a <code>user</code> will always have a <code>type</code>.</p> <p>The entire mapping works fine when reading some already-existing data from the DB. However, I run into problems when I attempt to insert a new record.</p> <p>Assume that the tables involved already have some records populated:</p> <pre><code>user |---------------------| | userID | userTypeID | |---------------------| | 1 | 1 | | 2 | 2 | | 3 | 2 | | 4 | 3 | |---------------------| admin |------------------| | adminID | userID | |------------------| | 1 | 4 | |------------------| employee |---------------------| | employeeID | userID | |---------------------| | 1 | 1 | | 2 | 2 | | 3 | 3 | |---------------------| manager |------------------------| | managerID | employeeID | |------------------------| | 1 | 1 | |------------------------| intern |-----------------------| | internID | employeeID | |-----------------------| | 1 | 2 | | 2 | 3 | |-----------------------| </code></pre> <p>If I were to create a new <code>intern</code> entity and persist it, I would expect three records to be inserted:</p> <pre><code>INSERT user ( userID, userTypeID ) VALUES ( 5, 2 ) INSERT employee ( employeeID, userID ) VALUES ( 4, 5 ) INSERT intern ( internID, employeeID ) VALUES ( 3, 4 ) </code></pre> <p>However, the SQL that actually gets executed is as follows:</p> <pre><code>INSERT user ( userID, userTypeID ) VALUES ( 5, 2 ) INSERT employee ( employeeID, userID ) VALUES ( 4, 5 ) INSERT intern ( internID, employeeID ) VALUES ( 3, 5 ) -- using the new userID instead of the new employeeID </code></pre> <p>Finally, the actual question:</p> <p>Why, when inserting into <code>intern</code>, is it using the <code>userID</code> instead of the <code>employeeID</code>? It's as if Hibernate is ignoring the <code>joincolumn</code> property on <code>intern</code> and just using the <code>joincolumn</code> from <code>employee</code>.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload