将子级添加到现有父级时休眠一对多完整性约束

时间:2019-01-19 14:44:27

标签: java hibernate jpa many-to-one hibernate-onetomany

我有一个Hibernate + Spring Boot应用程序,并且在通过添加子代更新父代时收到IntegrityConstraintViolationException。

数据库架构为:

table order (
  id (primary key auto generated),
);

table order_line (
  order_id (primary key + foreign key to order.id),
  order_line_id (primary key set manually set in the code),
)

在Java中:

@Getter
@Setter
@Entity(name = "ORDER")
public class Order {
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    private Integer id;


@Getter
@Setter
@Entity(name = "ORDER_LINE")
public class OrderLine implements Serializable{
    @Id
    private Integer orderLineId;
    @Id
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(referencedColumnName = "id", columnDefinition = "Integer", insertable = false, updatable = false)
    private Order order;

要创建订单,请使用JpaRepository并按以下方式创建对象:

    Order order = new Order();
    order.setId(118); //This is an existing order ID which should be updated
    Set<OrderLine> orderLines = new HashSet<OrderLine>();

    OrderLine orderLine = new OrderLine();
    orderLine.setOrderLineId(0); //This is an existing order line
    orderLine.setOrder(order);
    orderLines.add(orderLine);

    orderLine = new OrderLine();
    orderLine.setOrderLineId(1); //This is a non-existing order line
    orderLine.setOrder(order);
    orderLines.add(orderLine);

    order.setOrderLines(orderLines);

    orderRepository.save(order);

for (OrderLine orderLine : order.getOrderLines()) {
    orderLine.setOrder(order);
}
orderRepository.save(order);

此代码中有效的是:

  • 创建一个具有0个,1个或多个孩子的新父母(意思是,我没有设置orderId)

  • 更新父级字段和/或任何子级(在上面的示例中,如果我不添加第二个orderLine,一切正常)

  • 删除子行

但是行不通的是在现有父级中添加一行。这将导致以下异常:

  

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:   列“ ORDER_LINE_ID”不能为null   sun.reflect.NativeConstructorAccessorImpl.newInstance0(本机方法)

我不理解,因为我可以清楚地看到每个OrderLine对象的orderLineId设置正确。

我在做什么错了?

1 个答案:

答案 0 :(得分:1)

如果要将Order_id和order_line_id都作为OrderLine实体中的复合键,则需要首先创建一个@Embeddable

 @Embeddable
 public class OrderLinePK implements Serializable {
      private Integer orderId;
      private Integer orderLineId;
 } 

,然后在您的OrderLine实体中将其更改为

 @EmbeddedId
 private OrderLinePk pk;

 @MapsId("orderId")
 @ManyToOne
 private Order order;

现在每次您需要创建新的OrderLine时,都必须创建一个主键对象并分配ID,就像这样

 OrderLine orderLine = new OrderLine();
 OrderLinePK pk = new OrderLinePK();
 pk.setOrderLineId(11);
 orderLine.setPk(pk);
 orderLine.setOrder(order);

希望这会有所帮助。