不能使用<union-subclass>生成标识列密钥(TABLE_PER_CLASS)

88 inheritance hibernate jpa class-table-inheritance

com.something.SuperClass:

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class SuperClass implements Serializable {
    private static final long serialVersionUID = -695503064509648117L;

    long confirmationCode;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO) // Causes exception!!!
    public long getConfirmationCode() {
        return confirmationCode;
    }

    public void setConfirmationCode(long confirmationCode) {
        this.confirmationCode = confirmationCode;
    }
}
Run Code Online (Sandbox Code Playgroud)

com.something.SubClass:

@Entity
public abstract class Subclass extends SuperClass {
    private static final long serialVersionUID = 8623159397061057722L;

    String name;

    @Column(nullable = false)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
Run Code Online (Sandbox Code Playgroud)

给我这个例外:

Caused by: org.hibernate.MappingException: Cannot use identity column key
generation with <union-subclass> mapping for: com.something.SuperClass
Run Code Online (Sandbox Code Playgroud)

生成ID的最佳和最方便的方法是什么?我不想改变我的继承策略.

zoi*_*eck 212

这里的问题是你混合"每个表的表"继承和GenerationType.Auto.考虑MsSQL中的标识列.它是基于列的.在"每类表"策略中,每个类使用一个表,每个表都有一个ID.

尝试:

@GeneratedValue(strategy = GenerationType.TABLE)

  • 完美的解决方案。甚至 Hibernate 论坛似乎也没有这个解决方案,他们正在围绕这个话题 https://forum.hibernate.org/viewtopic.php?p=2319244&amp;sid=4493aa54d27d3f81a0e27ecbdda075ae (2认同)
  • 它完美地工作。但是,强烈建议不要使用 'TABLE' id 生成策略,因为它会触发大量查询(选择、插入和更新)并维护锁以为主键生成唯一值。那么如果我们有一个很大的继承场景,那么这个问题的替代解决方案是什么?它肯定会在很大程度上影响性能。 (2认同)

ski*_*box 8

我想知道这是否是一个数据库方言特定问题,因为观看一个使用PostgreSQL作为底层数据库的youtube教程,我看到视频的创建者成功运行了一个具有默认@GeneratedValue的应用程序.在我的情况下(底层数据库是MySQL)我必须完全按照zoidbeck的建议将@GeneratedValue策略修改为GenerationType.TABLE.

以下是视频:https://www.youtube.com/watch?v = qIdM4KQOtH8

  • 在PostgreSQL上,Hibernate默认使用`GenerationType.SEQUENCE`.这就是它在那里自动运作的原因.它绝对与PostgreSQL的"INHERITS"无关. (6认同)

Gon*_*ndy 7

同意 zoidbeck 的回答。您需要将策略更改为:

@GeneratedValue(strategy = GenerationType.TABLE)
Run Code Online (Sandbox Code Playgroud)

但这还不是全部,您需要创建一个新表,什么将保存您的摘要表的主键序列。将您的映射修改为

@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "ConfirmationCodeGenerator")
@TableGenerator(table = "SEQUENCES", name = "ConfirmationCodeGenerator")
public long getConfirmationCode() {
   return confirmationCode;
}
Run Code Online (Sandbox Code Playgroud)

数据库中的新表应如下所示: 在此处输入图片说明

当您运行您的应用程序时,Hibernate 将插入一行sequence_name实体名称(SuperClass在本例中),sequence_next_hi_value值将自动递增并用于所有实现子类表的新记录。