簡體   English   中英

是否可以映射(JPA)在抽象超類中使用泛型的Java類型層次結構?

[英]Is it possible to map (JPA) a Java type hierarchy that uses generics in the abstract superclass?

我一直在閱讀很多關於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抱怨ConcreteEntity1children映射。 它聲稱children的目標實體(BaseEntity)不是實體。 嗯,這是正確的,'BaseEntity'不是一個實體。 但實際的children類型不是 BaseEntity而是ConcreteEntity2 (由ConcreteEntity1的類型參數聲明)。

那么如何映射這樣的對象模型呢? 我已經嘗試了很多變化但沒有工作(它們都在實體管理器初始化期間失敗)。

我認為你幾乎所有東西都是正確的,除了在ConcreteEntity2正確擴展BaseEntity :你忘了說像public class ConcreteEntity2 extends 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 ),您必須使BaseEntity成為實體,或者引入另一個實體以由所有可能的子類擴展並使用它。 在上述任何一種情況下,您都必須使用JPA繼承。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM