I have tried the first apprach propposed by @Pascal Thivent
Here is what i have done (You can test if you want)
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public class Parent implements Serializable {
private Integer id;
private String parentField;
@Id
@GeneratedValue
public Integer getId() {
return id;
}
public String getParentProperty() {
return parentField;
}
}
Its Child subclass
@Entity
public class Child extends Parent {
private String childField;
public String getChildProperty() {
return childField;
}
}
And AnotherChild subclass
@Entity
public class AnotherChild extends Parent {
private String anotherChildField;
public String getAnotherChildProperty() {
return anotherChildField;
}
}
In order to test the first approach propposed by @Pascal Thivent, i have done as follows
public class LoadingParentObjectWhitoutAnySubclassTest {
private static final String QUERY_AGAINST_PARENT_CLASS = "from Parent p where p.id = :id and p.class = Parent";
private HibernateTemplate hibernateTemplate;
private Serializable savedParentId;
@BeforeClass
public void setUp() {
ApplicationContext appContext = new ClassPathXmlApplicationContext("app-persistence.xml");
hibernateTemplate = (HibernateTemplate) appContext.getBean("hibernateTemplate");
}
@BeforeMethod
public void createChild() {
Child child = new Child();
child.setParentProperty("something related to parent class");
child.setChildProperty("something related to Child class");
savedParentId = hibernateTemplate.save(child);
}
@Test
public void loadingParentWithoutAnySuclass {
Parent parent = (Parent) hibernateTemplate
.findByNamedParam(
QUERY_AGAINST_PARENT_CLASS,
"id",
savedParentId).get(0);
}
}
Hibernate logs
select
parent0_.id as id1_,
parent0_.parentProperty as parentPr2_1_,
parent0_1_.anotherChildProperty as anotherC2_2_,
parent0_2_.childProperty as childPro2_3_,
case
when parent0_1_.id is not null then 1
when parent0_2_.id is not null then 2
when parent0_.id is not null then 0
end as clazz_
from
Parent parent0_
/**
* Neither
*/
left outer join
AnotherChild parent0_1_
on parent0_.id=parent0_1_.id
/**
* Nor
*/
left outer join
Child parent0_2_
on parent0_.id=parent0_2_.id
/**
* is what i want to
*/
where
parent0_.id=?
and case
when parent0_1_.id is not null then 1
when parent0_2_.id is not null then 2
when parent0_.id is not null then 0
end=0
Therefore, i get the following Exception when i query against the Parent class
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
So, what have i done ?
I had to remodel inheritance as delegation See other drawbacks right here
@Entity
public class Parent implements Serializable {
private MutableInt id = new MutableInt();
private String parentField;
private ParentType parentType;
@Id
public Integer getId() {
return this.id.intValue();
}
public void setId(Integer id) {
this.id.setValue(id);
}
public setIdAsMutableInt(MutableInt id) {
this.id = id;
}
public String getParentProperty() {
return parentField;
}
@Enumerated(EnumType.STRING)
public ParentType getParentType() {
return parentType;
}
/**
* A marker enum to help to get our "subclass"
*/
public static enum ParentType {
CHILD,
ANOTHER_CHILD;
}
}
And Child class refactored
@Entity
public class Child implements Serializable {
private MutableInt id = new MutableInt();
private String childField;
private Parent parent;
@Transient
public MutableInt getIdAsMutableInt() {
return this.id;
}
@Id
@GeneratedValue
public Integer getId() {
return this.id.intValue();
}
public void setId(Integer id) {
this.id.setValue(id);
}
public String getChildProperty() {
return childField;
}
@OneToOne(fetch=fetch=FetchType.LAZY)
@PrimaryKeyJoinColumn
@Cascade(CascadeType.SAVE_UPDATE)
public Parent getParent() {
return this.parent;
}
}
To save our refactored code,
Child child = new Child();
Parent parent = new Parent();
parent.setParentType(ParentType.CHILD);
/**
* Workaround as a way both Parent and Child class share the same id
*/
parent.setIdAsMutableInt(child.getIdAsMutableInt());
Serializable savedId = hibernateTemplate.save(child);
Now it works fine!
Parent parent = hibernateTemplate.get(Parent.class, savedId);