用于扩展具有通用Id的基础实体的实体的Id映射

时间:2015-12-14 16:21:59

标签: java generics jpa

情境:JPA 2.1,实体扩展基础实体,通用ID

具有通用ID的Entity的接口:

public interface Entity<ID extends Serializable> extends Serializable {
    public ID getId();
    public void setId(ID id);
}

基础实现(摘要),定义了一些其他常见属性:

public abstract class BaseEntity<ID extends Serializable> implements Entity<ID> {

    private LocalDateTime creationTimestamp;
    private LocalDateTime lastModificationTimestamp;
    private Long version;
    private ID id;

    // getters and setters
}

一些具体实体:Person,其ID为UUID,在保留之前会被分配:

public class Person extends BaseEntity<UUID> {

    public Person() {
        setId(UUID.randomUUID());
    }
    // attributes, getters and setters
}

Address,其ID为Long并由序列生成:

public class Address extends BaseEntity<Long> {
    // attributes, getters and setters
}

O / R-映射:

    

<mapped-superclass class="idx.evaluation.jpa.hibernate.framework.BaseEntity">
    <attributes>
        <basic name="creationTimestamp">
            <column name="created" updatable="false" />
        </basic>
        <basic name="lastModificationTimestamp">
            <column name="last_modified" />
        </basic>
        <version name="version">
            <column name="version" />
        </version>
    </attributes>
</mapped-superclass>

<entity class="idx.evaluation.jpa.hibernate.model.Person">
    <table name="person" />
    <attributes>
        <id name="id">
            <column name="id" nullable="false" unique="true" />
        </id>
        <!-- more attributes -->
    </attributes>
</entity>

<entity class="idx.evaluation.jpa.hibernate.model.Address">
    <table name="address" />
    <attributes>
        <id name="id">
            <column name="id" nullable="false" unique="true" />
            <generated-value strategy="SEQUENCE" generator="id_sequence" />
        </id>
        <!-- more attributes -->
    </attributes>
</entity>

我的IDE(Eclipse 4.5)对PersonAddress的id属性发出警告:&#34;属性&#34; id&#34;是继承的;所有持久性可能都不支持引用orm.xml中的继承属性  提供者&#34;

运行测试时,我得到以下异常:

javax.persistence.PersistenceException: Unable to build entity manager factory
...
Caused by: org.hibernate.AnnotationException:
No identifier specified for entity: idx.evaluation.jpa.hibernate.model.Person

问题:我怎样才能实现这样的映射,其中基类定义了一个通用的Id属性,但每个子类的Id是不同的映射/生成的? 我在id上使用attribute-override做了另一次尝试,这适用于Person但不适用于Address(因为我无法为覆盖指定generated-value,但是想在那里使用一个序列。)

感谢任何帮助/提示,​​谢谢。

4 个答案:

答案 0 :(得分:2)

从JPA的角度来看,您无法按照您描述的方式定义两种身份策略。

不同的解决方案可能是BaseEntity进一步使用不同的身份策略进行子类化,例如IdentityBaseEntitySelfIdentifyingBaseEntity

从这一点开始,您的子类选择它希望子类化的标识父类。

答案 1 :(得分:1)

根据JPA 2.1. specifiaction

  

11.1.4 AttributeOverride注释

     

AttributeOverride注释用于覆盖a的映射   基本(无论是显式还是默认)属性或字段或 Id 属性   或领域。 ...

     

12.2.3.15 association-override   关联覆盖子元素是任何AssociationOverride或AssociationOverrides的附加元素   实体上的注释。它会覆盖任何AssociationOverride   相同属性名称的元素。如果是关联覆盖   存在子元素,以及它的属性或子元素   没有明确指定association-override子元素,它们是   应用默认值。

所以,你应该尝试这样的事情:

<entity class="idx.evaluation.jpa.hibernate.model.Person">
    <table name="person" />
    <attribute-override name="id">
         <column name="id" nullable="false" unique="true" />
    </attribute-override>
</entity>

<entity class="idx.evaluation.jpa.hibernate.model.Address">
    <table name="address" />
    <attribute-override name="id">
            <column name="id" nullable="false" unique="true" />
    </attribute-override>
    <attributes>
       <id name="id">
          <column name="id" nullable="false" unique="true" />
          <generated-value strategy="SEQUENCE" generator="id_sequence" />
       </id>
       <!-- more attributes -->
    </attributes>
</entity>

有关详细信息,请参阅hibernate手册中的this示例

答案 2 :(得分:1)

通过分割解决了BaseEntity两部分:一部分带有id(未映射),另一部分带有元数据(创建/修改时间戳和版本):

public abstract class EntityMetadata {
    private LocalDateTime creationTimestamp;
    private LocalDateTime lastModificationTimestamp;
    private Long version;
    // setters and getters
}

public abstract class BaseEntity<ID extends Serializable>
extends EntityMetadata implements Entity<ID> {
    private ID id;
    // setters and getters
}

EntityMetadata映射未定义Id ...

<mapped-superclass class="idx.evaluation.jpa.hibernate.framework.entity.EntityMetadata">
    <attributes>
        <basic name="creationTimestamp">
            <column name="created" updatable="false" />
        </basic>
        <basic name="lastModificationTimestamp">
            <column name="last_modified" />
        </basic>
        <version name="version">
            <column name="version" />
        </version>
    </attributes>
</mapped-superclass>

...允许PersonAddress定义他们喜欢的任何ID(名为"id"的属性,映射到具有生成值的任意列)。

对于JPA要识别的通用ID的实际类型,必须重写getId()方法以将结果缩小到实际类型:

public class Address extends BaseEntity<Long> {
    // ...
    @Override
    public Long getId() {
        return super.getId();
    }
    // ...
}

答案 3 :(得分:1)

我现在得到这个问题。最好的解决方案是注释:

  

@MappedSuperclass

     

指定一个类,其映射信息应用于从其继承的实体。映射的超类没有为其定义单独的表。

这是我的代码:

BaseEntity.java

@MappedSuperclass
public abstract class BaseEntity implements Serializable {

    public static final Timestamp DELETE_AT = Timestamp.valueOf("1970-01-01 00:00:00.0");

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(name = "`created_at`")
    private Timestamp createdAt;
}

Account.java

@Entity
@Table(name = "`accounts`")
public class Account extends BaseEntity {

    private Short status;

    private String email;
}

此代码没问题。

随着时间的推移,希望这可以帮助其他人