我有一个JPA实体的类层次结构,基类是MappedSuperclass,它定义了一个ID。我试图在子类中使用复合键,但似乎不起作用
我的代码看起来像这样
@MappedSuperclass
public class BaseEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "id")
protected Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
@Entity
@EntityListeners(EntityBaseListener.class)
@Inheritance(strategy=InheritanceType.JOINED)
@Table(name = "catalog_entity")
public class BaseCatalogEntity extends BaseEntity {
@Column(name = "created_at", nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date createdAt;
@Column(name = "updated_at", nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date updatedAt;
public void setCreatedAt(Date date)
{
createdAt = date;
}
public void setUpdatedAt(Date date)
{
updatedAt = date;
}
public Date getCreatedAt() {
return createdAt;
}
public Date getUpdatedAt() {
return updatedAt;
}
}
@Entity
@Table(schema = "student_catalog")
@IdClass(value = StudentCatalog.StudentCatalogPK.class)
public class StudentCatalog extends BaseCatalogEntity {
@Id
@Column(name = "name", nullable = false, length = 100)
private String name;
@Id
@Column(name = "version", nullable = false)
private Integer version;
@Column(name = "description" , length = 255)
private String description;
@Column(name = "vendor" , length = 50)
private String vendor;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getVersion() {
return version;
}
public void setVersion(Integer version) {
this.version = version;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getVendor() {
return vendor;
}
public void setVendor(String vendor) {
this.vendor = vendor;
}
public static class StudentCatalogPK implements Serializable {
private Long id;
private String name;
private Integer version;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getVersion() {
return version;
}
public void setVersion(Integer version) {
this.version = version;
}
@Override
public boolean equals(Object obj) {
boolean result = false;
if(obj != null && (obj instanceof StudentCatalogPK)) {
StudentCatalogPK other = (StudentCatalogPK)obj;
result = (Objects.equals(this.id, other.id) && Objects.equals(this.name, other.name) &&
Objects.equals(this.version, other.version));
}
return result;
}
@Override
public int hashCode() {
return (27780 + (this.id != null ? this.id.hashCode() : 0) +
(this.version != null ? this.version.hashCode() : 0) +
(this.name != null ? this.name.hashCode() : 0));
}
}
}
我得到以下异常:
异常说明:无效的复合主键规范。主键类[com.example.jpa.StudentCatalog $ StudentCatalogPK]中的主键字段或属性的名称以及实体bean类[class com.example.jpa.StudentCatalog]的名称必须对应,并且它们的类型必须是相同。另外,请确保您已为XML中的相应属性指定了ID元素,并且/或者在实体类的相应字段或属性上指定了@Id。
我正在使用Eclipselink 2.5.1。有没有办法在不改变BaseEntity和BaseCatalogEntity类的情况下让它工作?
答案 0 :(得分:0)
在JPA中重新定义子类中的id是不合法的。这将导致表映射以及多态查询中的歧义。
当业务密钥用于数据库身份时,扩展超类中定义的密钥的愿望是一个常见问题。我建议只使用代理键(如UUID)作为数据库标识,使用业务键作为实例标识。
答案 1 :(得分:0)
在以下条件下:
TABLE_PER_CLASS
继承(我可以看到它)您可以在类声明下使用@AttributeOverride
注释,从中删除@Id
个字段:
@AttributeOverride(name = "id", column = @Column(name = "NAME"))
这样 - 结果,可以更改派生实体表中的列名,这是你可以实现的最多。
答案 2 :(得分:0)
使用@MappedSuperClass时,建议将BaseEntity类设为抽象,然后从其他Entity类扩展Base类。
更清洁的方法牢记继承并设计应用程序。