允许使用 @GeneratedValue,即使列不是主键

Allow the use of @GeneratedValue even if column is not primary key

提问人:Abhishek 提问时间:4/18/2022 最后编辑:LaurelAbhishek 更新时间:11/10/2023 访问量:959

问:

我有一个实体类SupplierOrder.java其中包含两个字段:cuId 和 orderId

@Data
@EqualsAndHashCode(callSuper = false, of = { "cuId" })
@Builder(toBuilder = true)
@AllArgsConstructor
@Entity
@Table(name = "supplier_order")
public class SupplierOrder
{
        @Column(name = "cuid", nullable = false)
        private Long cuId;
    
        @Id
        @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "supOrd")
        @SequenceGenerator(name = "supOrd", sequenceName = "supplier_order_seq", allocationSize = 1 )
        @Column(name = "order_id", nullable = false)
        private Integer orderId;
}

当我保存我的实体时,用于对数据库进行以下操作

1. select next value for supplier_order_seq
2. insert into supplier_order(cuid,order_id)values(101,"<value from the point 1>")

现在,我必须翻转主键。换句话说,cuid 成为我的新主键,其余部分保持不变。

@Data
@EqualsAndHashCode(callSuper = false, of = { "orderId" })
@Builder(toBuilder = true)
@AllArgsConstructor
@Entity
@Table(name = "supplier_order")
public class SupplierOrder
{
        @Id                  //changed primary key from orderId to cuid
        @Column(name = "cuid", nullable = false)
        private Long cuId;
    
        @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "supOrd")
        @SequenceGenerator(name = "supOrd", sequenceName = "supplier_order_seq", allocationSize = 1 )
        @Column(name = "order_id", nullable = false)
        private Integer orderId;
}

现在,当我尝试保存我的实体时,会发生以下操作:

1. insert into supplier_order(cuid,order_id)values(101,NULL)

注意:从 seq supplier_order_seq获取下一个值不会发生,因此,它给了我错误,因为我无法order_id保存为 null。如何确保即使在更改主键后也应由 seq supplier_order_seq 提供order_id值?

我尝试从下面的链接中引用多种解决方案,但没有一个有效。

Java 休眠 spring-data-jpa 实体 序列

评论


答:

0赞 Ross Bu 11/10/2023 #1

2023 年,不确定是否为时已晚,以防万一有人需要,下面的解决方案无需额外的表实体即可生成 ID 假设你在 DB 中有一个生成器,那么你可以执行以下操作

      @GeneratedValue(generator = "table_id_seq_gen")
        @GenericGenerator(
                name = "table_id_seq_gen",
                strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
                parameters = {
                        @Parameter(name = SequenceStyleGenerator.SEQUENCE_PARAM, value = "table_id_seq"),
                        @Parameter(name = SequenceStyleGenerator.INCREMENT_PARAM, value = "10"),
// other params if needed
                })
        @Generated(GenerationTime.INSERT) // here is the trick
        private Long id;

然后,如果您有序列号bigSerial或sth,则可以这样做

@Column(name = "id", columnDefinition = "serial")
@Generated(GenerationTime.INSERT)
private Long id;

关键是 @Generated(GenerationTime.INSERT),所以总结一下

  • if by defautl not specified with @Generated(GenerationTime.INSERT) , 默认情况下,Hibernate 仅生成 PK。
  • 如果指定,它将 使用任何需要运行时插入的列。 @Generated(GenerationTime.INSERT)