我一直在阅读很多关于JPA映射的SO问题和博客文章和文档,但似乎没有什么能清楚地解决我的情况(这让我感到惊讶,因为我确信我不是第一个想要映射的人像这样的类层次结构。)
我有一个很好的,设计干净的对象模型,我需要通过JPA进行映射。它如下
public abstract class BaseEntity<T extends BaseEntity> {
private Integer id;
private List<T> children;
}
public class ConcreteEntity1 extends BaseEntity<ConcreteEntity2> {
private String value;
}
public class ConcreteEntity2 extends BaseEntity{
private String foo;
}
我似乎无法将其映射到地图上。我得到的最接近的是这样的(我现在正在使用XML映射,虽然我也尝试过注释):
<mapped-superclass class="com.me.datamodel.BaseEntity" access="FIELD">
<attributes>
<id name="id">
<column name="auto_id" nullable="false"/>
<generated-value strategy="IDENTITY"/>
</id>
</attributes>
</mapped-superclass>
<entity class="com.me.datamodel.ConcreteEntity1" access="FIELD">
<attributes>
<basic name="value" />
<one-to-many name="children" fetch="EAGER" mapped-by="media">
<cascade><cascade-all /></cascade>
</one-to-many>
</attributes>
</entity>
<entity class="com.me.datamodel.ConcreteEntity2" access="FIELD">
<attributes>
<basic name="foo" />
</attributes>
</entity>
问题在于JPA抱怨children
中ConcreteEntity1
的映射。它声称children
(BaseEntity)的目标实体不是实体。嗯,这是正确的,'BaseEntity'不是一个实体。但children
的实际类型不是 BaseEntity
,而是ConcreteEntity2
(由ConcreteEntity1
的类型参数声明)。
那么如何映射这样的对象模型呢?我已经尝试了很多变化,但都没有工作(它们都在实体管理器初始化期间失败)。
答案 0 :(得分:2)
我认为你几乎所有内容都是正确的,除了在BaseEntity
中正确延伸ConcreteEntity2
:你忘了说类型参数如public class ConcreteEntity2 extends BaseEntity<ConcreteEntity2> {...}
。因此,它无法映射ConcreteEntity2
,因此无法映射ConcreteEntity1
。
所以我的工作代码(使用EclipseLink 2.5.1和Hibernate 4.3.1.Final测试):
@MappedSuperclass
public abstract class BaseEntity<T extends BaseEntity> {
private Integer id;
private List<T> children;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@OneToMany(cascade=CascadeType.ALL)
public List<T> getChildren() {
return children;
}
public void setChildren(List<T> children) {
this.children = children;
}
}
@Entity
public class ConcreteEntity1 extends BaseEntity<ConcreteEntity2> {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
@Entity
public class ConcreteEntity2 extends BaseEntity<ConcreteEntity2> {
private String foo;
public String getFoo() {
return foo;
}
public void setFoo(String foo) {
this.foo = foo;
}
}
JPA尝试映射的每个实体中的一些重要说明,如果持久字段是集合,那么它必须是实体类型的集合(JPA规范章节 2.2持久字段和属性)。如果你不知道ConcreteEntity2
的孩子究竟是什么(除了他们是BaseEntity
),你必须要么BaseEntity
一个实体,要么引入另一个实体来扩展子类并改为使用它。在上述任何一种情况下,您都必须使用JPA继承。