情况: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(对 Person
和 Address
的 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
,该进一步细分为不同的身份策略,如IdentityBaseEntity
与SelfIdentifyingBaseEntity
。
从这一点开始,您的子类选择它希望子类的标识父类。
根据 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>
。允许Person
和Address
定义他们喜欢的任何 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;
}
此代码没问题。
随着时间的流逝,希望这可以帮助他人