使用JPA 1(hibernate-core版本3.3.0.SP1和hibernate-entitymanager版本3.4.0.GA): 我有一些类似于下面定义的实体,其中ChildOne和ChildTwo从父实体扩展。
@Entity
@Table(name = "TABLE_FATHER")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(discriminatorType = DiscriminatorType.INTEGER, name = Father.C_ID_CTG)
public class Father {
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "sq")
@Column(name = "ID_PK", nullable = false)
@BusinessId
private Long id;
...
}
@Entity
@Table(name = "TABLE_CHILD_ONE")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorValue(Categories.ID_CTG_ONE)
public class ChildOne extends Father {
...
}
@Entity
@Table(name = "TABLE_CHILD_TWO")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorValue(Categories.ID_CTG_TWO)
public class ChildTwo extends Element {
...
}
让我们说我有一个拥有父元素的实体,另一个拥有父元素的集合。在这两种情况下,应该去儿童实体。
@Entity
@Table(name = "TABLE_ONE")
public class OneTable {
@JoinColumn(name = "ID_PK", referencedColumnName = "ID_PK", nullable = false)
@ManyToOne(optional = false, fetch = FetchType.LAZY)
private Father element;
...
}
@Entity
@Table(name = "TABLE_ANOTHER")
public class Another {
@Fetch(FetchMode.JOIN)
@OneToMany(cascade = CascadeType.ALL, mappedBy = "id", fetch = FetchType.LAZY)
private Collection<Father> elementCollection;
...
}
我希望永远获得子元素但是当我得到元素getElement()
时返回父元素
而另一方面,当我收集集合getElementCollection()
时,子元素即将到来。
显然,@JoinColumn
是导致此行为的原因,与父表连接并忘记子元素。
该系列按预期工作。
如何通过getElement()
电话获取子元素?任何想法或workarround?
提前谢谢。
答案 0 :(得分:2)
问题不是由@JoinColumn
引起的。
原因是延迟加载。
我设法在更简单的例子中找出你的问题。
请原谅我将父亲的约定改为父母。
在下面的示例中,未初始化的元素是jpa.inheritance.issue.Parent_$$_javassist_1
的类型。它是一个Hibernate代理 - 动态创建的Parent子类。
你可以&#34; unproxy&#34;它通过调用Hibernate专有API getHibernateLazyInitializer().getImplementation()
。
elementCollection
的集合也是Lazy Initialized。集合的类型为org.hibernate.collection.PersistentBag
,在首次访问时使用正确的数据进行初始化。
集合一次初始化。
请查看使用您的确切版本的Hibernate(3.3.0.SP1 / 3.4.0.GA)成功通过绿色的测试。
@Test
public void test() {
Child c = new Child();
em.persist(c);
Another a = new Another();
a.setElement(c);
Collection<Parent> col = new ArrayList<Parent>();
col.add(c);
a.setElementCollection(col);
em.persist(a);
c.setAnother(a);
long idx = a.getId();
tx.commit();
// I'm cleaning the cache to be sure that call to a.getElement() will return proxy.
em.clear();
tx = em.getTransaction();
tx.begin();
a = em.find(Another.class, idx);
Assert.assertNotNull(a);
Parent p = a.getElement();
// At this point p is a type of jpa.inheritance.issue.Parent_$$_javassist_1
Assert.assertTrue(p instanceof Parent);
Assert.assertFalse(p instanceof Child);
// At this point a.elements is a not initialized (empty) collection of type org.hibernate.collection.PersistentBag
// When we access this collection for the first time, records are read from the database
Assert.assertEquals(1, a.getElementCollection().size());
if (p instanceof HibernateProxy) {
p =
(Parent) ((HibernateProxy) p).getHibernateLazyInitializer()
.getImplementation();
}
// At this point p is a type of jpa.inheritance.issue.Child
Assert.assertTrue(p instanceof Child);
}
@Entity
public class Another {
@JoinColumn(name = "element_id", referencedColumnName = "id", nullable = false)
@ManyToOne(fetch=FetchType.LAZY)
private Parent element;
public Parent getElement() {
return element;
}
public void setElement(Parent element) {
this.element = element;
}
@OneToMany(cascade = CascadeType.ALL, mappedBy = "another", fetch = FetchType.LAZY)
public Collection<Parent> elements;
public Collection<Parent> getElementCollection() {
return elements;
}
public void setElementCollection(Collection<Parent> elementCollection) {
this.elements = elementCollection;
}
// @Id ...
}
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Parent {
@ManyToOne
private Another another;
public Another getAnother() {
return another;
}
public void setAnother(Another another) {
this.another = another;
}
// @Id ...
}
@Entity
public class Child extends Parent {
}
您不需要@DiscriminatorColumn
或@DiscriminatorValue
因为InheritanceType.SINGLE_TABLE
需要这些注释作为确定类型的唯一手段。
使用InheritanceType.JOINED
Hibernate能够通过检查具有相同Id的(父表和子表)表中是否存在记录来确定多态类型。
您可以打开hibernate日志记录以查看查询如何确定类型。它的工作原理如下:
select
another0_.id as id0_1_,
another0_.element_id as element2_0_1_,
parent1_.id as id1_0_,
parent1_1_.name as name2_0_,
case
when parent1_1_.id is not null then 1
when parent1_.id is not null then 0
else -1
end as clazz_0_
from
Another another0_
inner join
Parent parent1_
on another0_.element_id=parent1_.id
left outer join
Child parent1_1_
on parent1_.id=parent1_1_.id
where
another0_.id=?