Hibernate, single table inheritance and using field from superclass as discriminator column
Solution 1
In my project it is done this way:
@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
}
And it works. I think your problem is that you needlessly define discriminator field in your superclass definition. Remove it and it will work.
Solution 2
In order to use a discriminator column as a normal property you should make this property read-only with insertable = false, updatable = false
. Since you can't change MappedSuperClass
, you need to use @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 {
...
}
Solution 3
You can map a database column only once as read-write field (a field that has insertable=true
and/or updatable=true
) and any number times as read-only field (insertable=false
and updatable=false
). Using a column as @DiscriminatorColumn
counts as read-write mapping, so you can't have additional read-write mappings.
Hibernate will set value specified in @DiscriminatorColumn
behind the scenes based on the concrete class instance. If you could change that field, it would allow modifying the @DiscriminatorColumn
field so that your subclass and value in the field may not match.
Comments
-
Juha Syrjälä almost 2 years
I have following kinds of classes for hibernate entity hierarchy. I am trying to have two concrete sub classes
Sub1Class
andSub2Class
. They are separated by a discriminator column (field
) that is defined inMappedSuperClass
. There is a abstract entity classEntitySuperClass
which is referenced by other entities. The other entities should not care if they are actually referencingSub1Class
orSub2Class
.It this actually possible? Currently I get this error (because column definition is inherited twice in Sub1Class and in EntitySuperClass) :
Repeated column in mapping for entity: my.package.Sub1Class column: field (should be mapped with insert="false" update="false")
If I add
@MappedSuperClass
toEntitySuperClass
, then I get assertion error from hiberante: it does not like if a class is both Entity and a mapped super class. If I remove@Entity
fromEntitySuperClass
, the class is no longer entity and can't be referenced from other entities:MappedSuperClass
is a part of external package, so if possible it should not be changed.My classes:
@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; } }
-
Clint Eastwood about 4 yearsI don't think that calling a method from within an annotation would work in Java.