使用通用 ID 扩展基本实体的实体的 ID 映射



情况: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 属性发出警告:">
属性 'id' 是继承的;引用 ORM 中的继承属性.xml可能并非全部持久化都支持该属性 供应商">

运行测试时,出现以下异常:

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,但想在那里使用序列(。

任何帮助/提示不胜感激,谢谢。

从 JPA 的角度来看,您不能以您所描述的方式定义两种标识策略。

一个不同的解决方案可能是有一个BaseEntity,该进一步细分为不同的身份策略,如IdentityBaseEntitySelfIdentifyingBaseEntity

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

根据 JPA 2.1. 指定:

11.1.4 属性覆盖注解

属性覆盖注释用于覆盖 基本(无论是显式还是默认(属性或字段或 Id 属性 或字段。 ...

12.2.3.15 关联覆盖 关联覆盖子元素是任何关联覆盖或关联覆盖的附加项 实体上的批注。它覆盖任何关联覆盖 元素,以显示相同的属性名称。如果关联覆盖 子元素存在,并且其属性或子元素 关联覆盖子元素未显式指定,其 应用默认值。

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

<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>

有关详细信息,请参阅休眠手册中的此示例

通过将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
}

实体元数据映射未定义 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();
    }
    // ...
}

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

@MappedSuperclass

指定一个类,该类的

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

这是我的代码:

基本实体.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;
}

帐户.java

@Entity
@Table(name = "`accounts`")
public class Account extends BaseEntity {
    private Short status;
    private String email;
}

此代码没问题。

随着时间的流逝,希望这可以帮助他人

最新更新