Java JPA继承问题
使用JPA1(hibernate core版本3.3.0.SP1和hibernate entitymanager版本3.4.0.GA): 我有一些类似于下面定义的实体,其中ChildOne和ChildTwo扩展自父实体Java JPA继承问题,java,hibernate,inheritance,jpa,Java,Hibernate,Inheritance,Jpa,使用JPA1(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 = Discriminator
@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;
...
}
@实体
@表(name=“Table_ONE”)
公共类一表{
@JoinColumn(name=“ID\u PK”,referencedColumnName=“ID\u PK”,nullable=false)
@ManyToOne(可选=false,fetch=FetchType.LAZY)
私人父亲因素;
...
}
@实体
@表(name=“Table_其他”)
公开课{
@Fetch(FetchMode.JOIN)
@OneToMany(cascade=CascadeType.ALL,mappedBy=“id”,fetch=FetchType.LAZY)
私人收藏元素收藏;
...
}
我希望总是获得子元素,但当我获得元素getElement()
时,返回父元素
另一方面,当我得到集合getElementCollection()
时,子元素就来了
显然,@JoinColumn
是这种行为的原因,它与父表进行连接,而忘记了子元素。
集合正在按预期工作
如何通过调用getElement()
获取children元素?有什么想法或想法吗?
提前感谢。问题不是由
@JoinColumn
引起的。
原因是延迟加载。
我设法用一个简单的例子指出了你的问题。
原谅我把传统从父亲改为父母
在下面的示例中,未初始化元素的类型为jpa.heritation.issue.Parent\u$$\ uJavassist\u1
。它是一个Hibernate代理-动态创建的父类的子类。
您可以通过调用Hibernate专有APIgetHibernateLazyInitializer().getImplementation()
来“取消固定”它
elementCollection
的集合也已初始化。集合的类型是org.hibernate.collection.PersistentBag
,在首次访问时,它将使用正确的数据初始化。
集合一次全部初始化。
请查看与您的Hibernate(3.3.0.SP1/3.4.0.GA)完全相同的版本成功通过绿色测试的测试
只是一些关于你答案的注释。。。据我所知,规范不要求实现使用鉴别器列来实现连接继承,但是,假设是如果指定了@DiscriminatorColumn,那么将使用它。。。另一方面,尽管你的解决方案确实有效,但仍然有一些疑问。知道懒人会返回代理,为什么很多人会将代理返回给父代(jpa.heritation.issue.parent\u$$\ ujavassist\u1)和OneToMany集合子代(jpa.heritation.issue.ChildOne\u$$\ ujavassist\u1)??实际应用程序中
getElement()
调用的确切返回类型是不确定的。原因如果在一级或二级缓存中找到该对象,则该对象的类型将为子对象。这就是为什么我在中间调用<代码> EM.CULL()和代码>来确定特定的行为。这就是为什么在父子层次结构的情况下最好是类型不可知的。如果你真的需要一个正确的类型,你可以像我建议的那样“取消固定”,或者最好将FetchType改为“渴望”(因为“取消固定”加载关系)。关于ManyTone,我将在不久的将来发布一些信息。你的评论很有趣!非常感谢您抽出时间!但这是另一件我不太确定的事情。。。我已经尝试将FetchType更改为Eager(这是我的第一个选项),但仍然有相同的行为(这意味着,使用Eager fetching的集合仍然以相同的方式返回代理元素)em.clean()?我猜你是指他们。明白了。。。我也考虑过这一点,但它不适用于我的特定情况(但我知道这可能是一个选项)是的,em.clear()
。但这还不够。为了可靠地通过测试,我必须关闭二级缓存,清除EntityManager并重新启动事务。。。我不推荐在生产中使用。您确定必须依赖于确切的类型吗?也许是时候重新设计了?
@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 {
}
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=?