I have two classes, Employee and Manager. Manager extends Employee, as it is a type of employee. Employee has an instance of Manager, which represents the idea of an employee having one manager. Conversely, manager has a set of Employees. There are two tables, EMPLOYEE and MANAGER:
table EMPLOYEE
long ID
varchar NAME
long MANAGERID
table MANAGER
long ID
long EMPLOYEEID //a join on this field enables inheritance
The classes look like this:
Employee.java (setters and getters omitted for brevity):
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Table(name = "EMPLOYEE", schema = "TEST01")
public class Employee extends hata.util.Entity implements java.io.Serializable {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "ID", unique = true, nullable = false)
protected Long id;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "MANAGERID")
protected Manager manager;
@Column(name = "FIRSTNAME", nullable = false, length = 50)
protected String firstname;
Manager.java
@Entity
@PrimaryKeyJoinColumn(name="EMPLOYEEID")
@Table(name = "MANAGER", schema = "TEST01")
public class Manager extends Employee implements java.io.Serializable {
@OneToMany(fetch = FetchType.LAZY, mappedBy = "manager")
private Set<Employee> employees = new HashSet<Employee>(0);
I have filled the tables with a few employees, and all of those employees have the same manager, except for one employee – the one who is the manager. He himself has no manager. (If you’re following me correctly, then it should be obvious that I have 1 row in the manager table, with and EMPLOYEEID referring back to a row in the EMPLOYEE table that has null as it’s MANAGERID).
So, this setup looked correct to me, however when I tried to query all Employee objects with:
Query q = em.createQuery("select em from Employee em");
result = (List<Employee>) q.getResultList();
I get a nasty stack trace:
Caused by: org.hibernate.PropertyAccessException: could not set a field value by reflection setter of hata.staff.entity.Employee.manager
at org.hibernate.property.DirectPropertyAccessor$DirectSetter.set(DirectPropertyAccessor.java:151)
at org.hibernate.tuple.entity.AbstractEntityTuplizer.setPropertyValues(AbstractEntityTuplizer.java:586)
at org.hibernate.tuple.entity.PojoEntityTuplizer.setPropertyValues(PojoEntityTuplizer.java:231)
at org.hibernate.persister.entity.AbstractEntityPersister.setPropertyValues(AbstractEntityPersister.java:3824)
at org.hibernate.engine.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:153)
at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:898)
at org.hibernate.loader.Loader.doQuery(Loader.java:773)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:270)
at org.hibernate.loader.Loader.doList(Loader.java:2294)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2172)
at org.hibernate.loader.Loader.list(Loader.java:2167)
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:448)
at org.hibernate.hql.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:363)
at org.hibernate.engine.query.HQLQueryPlan.performList(HQLQueryPlan.java:196)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1258)
at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)
at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:236)
… 108 more
Caused by: java.lang.IllegalArgumentException: Can not set hata.staff.entity.Manager field hata.staff.entity.Employee.manager to hata.staff.entity.Employee
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:164)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:168)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
at java.lang.reflect.Field.set(Field.java:680)
at org.hibernate.property.DirectPropertyAccessor$DirectSetter.set(DirectPropertyAccessor.java:139)
… 124 more
Did I code this wrong, or can hibernate simply not handle this scenario? I’d appreciate any assistance.
The
EMPLOYEEIDcolumn in manager shouldn’t be there.@PrimaryKeyJoinColumnmeans that the primary key is also the join column. So, theIDcolumn inMANAGERis both the primary key and the foreign key toEMPLOYEE.And the annotation should of course be changed to
@PrimaryKeyJoinColumn(name="ID")(or it must be removed, since the default is to use the same column name as in the parent table)See http://download.oracle.com/javaee/6/api/javax/persistence/PrimaryKeyJoinColumn.html.