Hibernate: What is wrong with this mapping to the subclass associated with the foreign key?

I am experimenting with Hibernate to gain experience. I created the Person class with two subclasses: Student and Worker :

 public abstract class Person { private Long id; ... } public class Student extends Person { ... } 

The other Employer class has a one-to-many bidirectional relationship with Worker .

 public class Worker extends Person { private Employer employer; ... } public class Employer { private String taxId; private Set<Worker> employees = new HashSet<Worker>(); ... } 

for which the mapping

 <class name="Employer" table="EMPLOYER"> <id name="taxId" column="TAX_ID" length="11"> <generator class="assigned"/> </id> ... <set name="employees" inverse="true"> <key column="EMPLOYER_TAX_ID"/> <one-to-many class="Worker"/> </set> </class> 

The inheritance hierarchy is modeled with a mixed strategy, where Student mapped to the Person table, but the Worker is stored in its own table, connected to a foreign key:

 <class name="Person" table="PERSON"> <id name="id" column="PERSON_ID" type="long" unsaved-value="0"> <generator class="native"/> </id> <discriminator column="PERSON_TYPE" type="string"/> ... <subclass name="Student" discriminator-value="STU"> ... </subclass> <subclass name="Worker" discriminator-value="WRK"> <join table="WORKER"> <key column="WORKER_ID"/> <many-to-one name="employer" column="EMPLOYER_TAX_ID" cascade="save-update"/> ... </join> </subclass> </class> 

I am using Apache Derby 10.5.3.0 and auto-generating the scheme by setting hibernate.hbm2ddl.auto to create-drop .

To test all this, I created a DBUnit test with the following dataset:

 <EMPLOYER TAX_ID = "1234567890" ... /> <PERSON PERSON_ID = "12345" PERSON_TYPE = "WRK" ... /> <WORKER WORKER_ID = "12345" EMPLOYER_TAX_ID = "1234567890" ... /> 

I have a test that loads a work object and verifies that it has the right employee. It passes. Then test in the opposite direction:

  String taxId = "1234567890"; Employer employer = (Employer) session.get(Employer.class, taxId); assertNotNull(employer); assertThat(employer.getEmployees().size(), is(1)); 

The last statement fails because the recruitment is empty.

Digging deeper, I found that for some reason, Hibernate is looking for (and creating) the EMPLOYER_TAX_ID column in the PERSON table instead of WORKER ! It is also present in WORKER, but this one is not used in the request. Select statements to populate a set of employees:

 select employees0_.EMPLOYER_TAX_ID as EMPLOYER10_1_, employees0_.PERSON_ID as PERSON1_1_, employees0_.PERSON_ID as PERSON1_1_0_, employees0_.FIRST_NAME as FIRST3_1_0_, employees0_.FAMILY_NAME as FAMILY4_1_0_, employees0_.DATE_OF_BIRTH as DATE5_1_0_, employees0_.HOME_ADDRESS as HOME6_1_0_, employees0_.CITY as CITY1_0_, employees0_.ZIP as ZIP1_0_, employees0_1_.EMPLOYER_TAX_ID as EMPLOYER2_2_0_, employees0_1_.JOB_TITLE as JOB3_2_0_, employees0_1_.JOB_GRADE as JOB4_2_0_, employees0_1_.START_DATE as START5_2_0_ from PERSON employees0_ inner join WORKER employees0_1_ on employees0_.PERSON_ID=employees0_1_.WORKER_ID where employees0_.EMPLOYER_TAX_ID=? 

Why is this? And , how can I get Hibernate to find EMPLOYER_TAX_ID in the WORKER table?

Please note that since this is a pilot project, I can change something. I appreciate any workarounds, but I would prefer to understand what is happening and fix this mapping as is (as much as possible).

Update: if I switch to a pure <joined-subclass> inheritance matching strategy, the generated circuit looks as it should, and the test passes. This is a pretty good workaround, but I'm still wondering if there is a way for the mixed strategy to work properly.

+6
java inheritance mapping hibernate one-to-many
source share
2 answers

This sounds like a known bug: http://opensource.atlassian.com/projects/hibernate/browse/HHH-1015

It is known with age and has been reported many times. However, they do not fix it ...

+2
source share

I had the same problem and fixed it as follows:
Changing a subclass to a merged sublclass.
In your case, it will be:

 <joined-subclass name="Worker" table="WORKER"> <key column="WORKER_ID"/> <many-to-one name="employer" column="EMPLOYER_TAX_ID" cascade="save-update"/> ... </joined-subclass> 

Hope this helps.

0
source share

All Articles