如何为@OneToOne关联表配置ID及序列生成器?
问题
能不能像为表A和表B配置@SequenceGenerator注解那样,为@OneToOne关联表配置标识符及其序列生成器?目前Hibernate未获取下一个标识符(nextval),导致关联表插入时未赋值ID,触发ORA-01400错误:无法在"user"."ASSOCIATION_TABLE"."ID_ASSOCIATION"中插入NULL。
Hibernate生成的插入SQL如下:
insert into ASSOCIATION_TABLE (ID_TABLE_A, ID_TABLE_B) values (123, 456);
原实体类代码
实体A
@Entity @Table(name = "TABLE_A") public class TableA { @Id @Column(name = "ID_TABLE_A", length = 20) @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "TABLE_A_SEQ") @SequenceGenerator(sequenceName = "TABLE_A_SEQ", allocationSize = 1, name = "TABLE_A_SEQ") private Long id; @OneToOne(cascade = CascadeType.ALL) @JoinTable( name = "ASSOCIATION_TABLE", joinColumns = @JoinColumn(name = "ID_TABLE_A", referencedColumnName = "ID_TABLE_A"), inverseJoinColumns = @JoinColumn(name = "ID_TABLE_B", referencedColumnName = "ID_TABLE_B") ) private TableB b; // getters and setters }
实体B
@Entity @Table(name = "TABLE_B") public class TableB { @Id @Column(name = "ID_TABLE_B", length = 20) @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "TABLE_B_SEQ") @SequenceGenerator(sequenceName = "TABLE_B_SEQ", allocationSize = 1, name = "TABLE_B_SEQ") private Long id; @OneToOne(mappedBy = "b") private TableA a; // getters and setters }
解决方案
@JoinTable是Hibernate用于自动管理关联关系的机制,它默认仅维护两个外键的关联,不会处理中间表的额外字段(比如独立ID)。如果你的关联表必须有自增的独立ID字段,需要将该关联表单独映射为实体类,而非依赖@JoinTable自动生成。
步骤1:创建关联表实体类
将ASSOCIATION_TABLE映射为独立实体,配置ID的序列生成器:
@Entity @Table(name = "ASSOCIATION_TABLE") public class AssociationTable { @Id @Column(name = "ID_ASSOCIATION", length = 20) @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ASSOCIATION_SEQ") @SequenceGenerator(sequenceName = "ASSOCIATION_SEQ", allocationSize = 1, name = "ASSOCIATION_SEQ") private Long id; @OneToOne @JoinColumn(name = "ID_TABLE_A", referencedColumnName = "ID_TABLE_A") private TableA tableA; @OneToOne @JoinColumn(name = "ID_TABLE_B", referencedColumnName = "ID_TABLE_B") private TableB tableB; // getters and setters }
步骤2:修改原实体的关联关系
去掉@JoinTable,改为关联新创建的AssociationTable实体:
修改后的TableA
@Entity @Table(name = "TABLE_A") public class TableA { @Id @Column(name = "ID_TABLE_A", length = 20) @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "TABLE_A_SEQ") @SequenceGenerator(sequenceName = "TABLE_A_SEQ", allocationSize = 1, name = "TABLE_A_SEQ") private Long id; @OneToOne(mappedBy = "tableA", cascade = CascadeType.ALL) private AssociationTable association; // 可选:添加便捷方法直接操作TableB public TableB getTableB() { return association != null ? association.getTableB() : null; } public void setTableB(TableB tableB) { if (association == null) { association = new AssociationTable(); association.setTableA(this); } association.setTableB(tableB); tableB.setAssociation(association); } // getters and setters }
修改后的TableB
@Entity @Table(name = "TABLE_B") public class TableB { @Id @Column(name = "ID_TABLE_B", length = 20) @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "TABLE_B_SEQ") @SequenceGenerator(sequenceName = "TABLE_B_SEQ", allocationSize = 1, name = "TABLE_B_SEQ") private Long id; @OneToOne(mappedBy = "tableB", cascade = CascadeType.ALL) private AssociationTable association; // getters and setters }
原理说明
将关联表映射为独立实体后,你可以完全控制它的字段生成逻辑,包括通过序列生成ID。Hibernate会在插入该实体时自动调用序列获取nextval,避免NULL插入错误。
内容的提问来源于stack exchange,提问作者Gabriel Bento
相关产品推荐
相关产品推荐

