Hibernate,单表继承并使用超类中的字段作为鉴别列

发布于 2024-09-10 07:13:48 字数 2885 浏览 8 评论 0原文

我有以下类型的休眠实体层次结构类。我试图有两个具体的子类 Sub1ClassSub2Class。它们由 MappedSuperClass 中定义的鉴别器列 (field) 分隔。有一个抽象实体类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 收到断言错误:不喜欢一个类既是实体又是映射的超类。如果我从 EntitySuperClass 中删除 @Entity,该类就不再是实体,并且不能从其他实体引用:

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

}

I have following kinds of classes for hibernate entity hierarchy. I am trying to have two concrete sub classes Sub1Class and Sub2Class. They are separated by a discriminator column (field) that is defined in MappedSuperClass. There is a abstract entity class EntitySuperClass which is referenced by other entities. The other entities should not care if they are actually referencing Sub1Class or Sub2Class.

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 to EntitySuperClass, 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 from EntitySuperClass, 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;
    }

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

驱逐舰岛风号 2024-09-17 07:13:48

在我的项目中,它是这样完成的:

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

并且它有效。我认为你的问题是你在超类定义中不必要地定义了鉴别器字段。将其删除即可工作。

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.

生生漫 2024-09-17 07:13:48

为了将鉴别器列用作普通属性,您应该使用 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 { 
    ...
}

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 { 
    ...
}
窝囊感情。 2024-09-17 07:13:48

您只能将数据库列映射为读写字段(具有 insertable=true 和/或 updatable=true 的字段)一次,并且可以多次映射为只读字段(insertable=false updatable=false)。使用列作为 @DiscriminatorColumn 算作读写映射,因此您不能拥有额外的读写映射。

Hibernate 将根据具体类实例在幕后设置 @DiscriminatorColumn 中指定的值。如果您可以更改该字段,则将允许修改 @DiscriminatorColumn 字段,以便您的子类和该字段中的值可能不匹配。

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.

预谋 2024-09-17 07:13:48

一个基本原则:您实际上不需要从数据库检索您的鉴别器列。您应该已经在代码中包含了该信息,并在 @DiscriminatorValue 标记中使用了这些信息。如果您需要从数据库中读取该信息,请仔细考虑您分配鉴别器的方式。

如果您在最终实体对象中需要它,一种好的做法是从鉴别器值实现枚举并将其返回存储在 @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; }
}

One fundamental: You effectively should not need to retrieve your discriminator column from DB. You should already have that information within the code, of which you use in your @DiscriminatorValue tags. If you need read that from DB, reconsider carefully the way you are assigning discriminators.

If you need it in final entity object, one good practice can be to implement an Enum from discriminator value and return store it in a @Transient field:

@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; }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文