我有以下几种用于hibernate实体层次结构的类。我想要有两个具体的子类Sub1Class
和Sub2Class
。它们由field
中定义的鉴别器列(MappedSuperClass
)分隔。有一个抽象的实体类EntitySuperClass
,由其他实体引用。其他实体不应该关心它们是否实际引用Sub1Class
或Sub2Class
。
这实际上可能吗?目前我收到此错误(因为列定义在Sub1Class和EntitySuperClass中继承两次):
Repeated column in mapping for entity: my.package.Sub1Class column: field (should be mapped with insert="false" update="false")
如果我将@MappedSuperClass
添加到EntitySuperClass
,那么我会从hiberante得到断言错误:它不喜欢一个类是实体还是映射的超类。如果我从@Entity
中删除EntitySuperClass
,则该类不再是实体,也无法从其他实体引用:
MappedSuperClass
是外部包的一部分,因此如果可能,则不应更改。
我的课程:
@MappedSuperclass
public class MappedSuperClass {
private static final String ID_SEQ = "dummy_id_seq";
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = ID_SEQ)
@GenericGenerator(name=ID_SEQ, strategy="sequence")
@Column(name = "id", unique = true, nullable = false, insertable = true, updatable = false)
private Integer id;
@Column(name="field", nullable=false, length=8)
private String field;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
}
@Entity
@Table(name = "ACTOR")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="field", discriminatorType=DiscriminatorType.STRING)
abstract public class EntitySuperClass extends MappedSuperClass {
@Column(name="description", nullable=false, length=8)
private String description;
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
@Entity
@DiscriminatorValue("sub1")
public class Sub1Class extends EntitySuperClass {
}
@Entity
@DiscriminatorValue("sub2")
public class Sub2Class extends EntitySuperClass {
}
@Entity
public class ReferencingEntity {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Integer id;
@Column
private Integer value;
@ManyToOne
private EntitySuperClass entitySuperClass;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
}
public EntitySuperClass getEntitySuperClass() {
return entitySuperClass;
}
public void setEntitySuperClass(EntitySuperClass entitySuperClass) {
this.entitySuperClass = entitySuperClass;
}
}
答案 0 :(得分:15)
在我的项目中,这样做:
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "field", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorValue("dummy")
public class EntitySuperClass {
// here definitions go
// but don't define discriminator column here
}
@Entity
@DiscriminatorValue(value="sub1")
public class Sub1Class extends EntitySuperClass {
// here definitions go
}
它有效。我认为你的问题是你在超类定义中不必要地定义了鉴别器字段。删除它,它会工作。
答案 1 :(得分:13)
为了将鉴别器列用作普通属性,您应该使用insertable = false, updatable = false
将此属性设置为只读。由于您无法更改MappedSuperClass
,因此您需要使用@AttributeOverride
:
@Entity
@Table(name = "ACTOR")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="field", discriminatorType=DiscriminatorType.STRING)
@AttributeOverride(name = "field",
column = @Column(name="field", nullable=false, length=8,
insertable = false, updatable = false))
abstract public class EntitySuperClass extends MappedSuperClass {
...
}
答案 2 :(得分:2)
您只能将数据库列映射一次作为读写字段(具有insertable=true
和/或updatable=true
的字段)和任意次数作为只读字段(insertable=false
和 updatable=false
)。使用@DiscriminatorColumn
列作为读写映射计数,因此您无法进行其他读写映射。
Hibernate将根据具体的类实例在幕后设置@DiscriminatorColumn
中指定的值。如果您可以更改该字段,则可以修改@DiscriminatorColumn
字段,以便您的子类和字段中的值可能不匹配。
答案 3 :(得分:0)
一个基本原则:您实际上不需要从DB检索您的鉴别器列。您应该已经在代码中拥有了这些信息,您在@DiscriminatorValue标记中使用了这些信息。如果您需要从DB中读取,请仔细重新考虑您分配鉴别器的方式。
如果在最终实体对象中需要它,一个好的做法是从鉴别器值实现Enum并将其存储在@Transient字段中:
@Entity
@Table(name="tablename")
@DiscriminatorValue(Discriminators.SubOne.getDisc())
public class SubClassOneEntity extends SuperClassEntity {
...
@Transient
private Discriminators discriminator;
// Setter and Getter
...
}
public enum Discriminators {
SubOne ("Sub1"),
SubOne ("Sub2");
private String disc;
private Discriminators(String disc) { this.disc = disc; }
public String getDisc() { return this.disc; }
}