Spring 引导 JPA 如何处理 child table 更新
Spring Boot JPA how to handle child table updates
我以前的工作背景是使用所有自定义 SQL 和 JDBC 进行所有数据持久化。刚开始为一家小型企业开展新工作,我是其中唯一的开发人员,并决定使用 Spring 使用 JPA 引导开发业务系统以实现数据持久性。
我不知道我应该如何处理 child table 上的更新。我目前正在使用 Spring Crud 存储库进行基本 tables,但我已经建立了我的第一个 parent child 关系。
给定以下示例 table 结构,我应该如何管理更新?
+-------------------------+
| Order |
+-------------------------+
| orderNumber | PK |
+-------------------------+
+-------------------------+
| OrderLine |
+-------------------------+
| orderNumber | PK |
+-------------------------+
| lineNumber | PK |
+-------------------------+
用户可以更新或删除现有的订单行。
进行更新时,我可以先删除所有现有的 orderLine,然后重新创建它们,但不确定这是否是不好的做法?
使用 Spring Boot 和 JPA 的正常方法是什么?
我应该在 parent 实体上使用某种级联设置吗?
你能把 orderNumber
换成 orderId
吗?通过外键 orderId
对 Order
table 的 orderLine
table 引用对您的代码具有更多意义。如果可以,使用连接列和级联配置,而不是删除所有 orderLine
并重新创建它们,让 JPA 为您完成。
您可以在 Spring Data JPA 中为您的实体执行以下映射以复制上述要求。您正在尝试的是 Order
和 OrderLine
之间的组合关系,其中前者是所有者而不是 parent/child 关系。
@Entity
@Table(name="Order")
class Order {
@Id
private Long orderNumber;
@OneToMany(mappedBy="order")
private List<OrderLine> orderLines;
}
@Entity
@Table(name="OrderLine")
class OrderLine {
@ManyToOne
@JoinColumn(name="orderNumber", nullable=false)
private Order order;
private Long lineNumber;
}
When doing an update, I could delete all of the existing orderLines first and recreate them but not sure if this is bad practice?
最好只更新需要更新的订单行。
I could delete all of the existing orderLines first and recreate them
这会导致进行大量删除查询和大量插入查询,这很糟糕。订单行的自动生成 id
也会迅速增加,这不是您想要的。
What is the normal approach with Spring Boot and JPA?
Should I be using some kind of cascade settings on the parent entity?
是的,你应该。这是一个例子:
Order.java
@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long orderNumber;
@Version
private Long version = 0L;
@OneToMany(mappedBy="order", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<OrderLine> orderLines;
// equals() and hashcode() implementation
// getter() and setter() implementation
}
OrderLine.java
@Entity
public class OrderLine {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long lineNumber;
@ManyToOne
@JoinColumn(name="order_id", nullable=false)
private Order order;
@Version
private Long version = 0L;
// equals() and hashcode() implementation
// getter() and setter() implementation
}
最后是一个更新示例:
public boolean update(Order order, long orderLineId, OrderLine updatedOrderLine) {
if(order == null || updatedOrderLine == null)
return false;
if(order.getOrderLines() == null)
return false;
Optional<OrderLine> optTargetOrderLine = order.getOrderLines().stream()
.filter(orderline -> orderLine.getLineNumber() == orderLineId).findFirst();
if(!optTargetOrderLine.isPresent())
return false;
OrderLine targetOrderLine = optTargetOrderLine.get();
// now implement the update function
boolean status = update(targetOrderLine, updatedOrderLine);
// if status is true, you also have to call save() on your OrderRepository
return status;
}
我以前的工作背景是使用所有自定义 SQL 和 JDBC 进行所有数据持久化。刚开始为一家小型企业开展新工作,我是其中唯一的开发人员,并决定使用 Spring 使用 JPA 引导开发业务系统以实现数据持久性。
我不知道我应该如何处理 child table 上的更新。我目前正在使用 Spring Crud 存储库进行基本 tables,但我已经建立了我的第一个 parent child 关系。
给定以下示例 table 结构,我应该如何管理更新?
+-------------------------+ | Order | +-------------------------+ | orderNumber | PK | +-------------------------+ +-------------------------+ | OrderLine | +-------------------------+ | orderNumber | PK | +-------------------------+ | lineNumber | PK | +-------------------------+
用户可以更新或删除现有的订单行。
进行更新时,我可以先删除所有现有的 orderLine,然后重新创建它们,但不确定这是否是不好的做法?
使用 Spring Boot 和 JPA 的正常方法是什么?
我应该在 parent 实体上使用某种级联设置吗?
你能把 orderNumber
换成 orderId
吗?通过外键 orderId
对 Order
table 的 orderLine
table 引用对您的代码具有更多意义。如果可以,使用连接列和级联配置,而不是删除所有 orderLine
并重新创建它们,让 JPA 为您完成。
您可以在 Spring Data JPA 中为您的实体执行以下映射以复制上述要求。您正在尝试的是 Order
和 OrderLine
之间的组合关系,其中前者是所有者而不是 parent/child 关系。
@Entity
@Table(name="Order")
class Order {
@Id
private Long orderNumber;
@OneToMany(mappedBy="order")
private List<OrderLine> orderLines;
}
@Entity
@Table(name="OrderLine")
class OrderLine {
@ManyToOne
@JoinColumn(name="orderNumber", nullable=false)
private Order order;
private Long lineNumber;
}
When doing an update, I could delete all of the existing orderLines first and recreate them but not sure if this is bad practice?
最好只更新需要更新的订单行。
I could delete all of the existing orderLines first and recreate them
这会导致进行大量删除查询和大量插入查询,这很糟糕。订单行的自动生成 id
也会迅速增加,这不是您想要的。
What is the normal approach with Spring Boot and JPA? Should I be using some kind of cascade settings on the parent entity?
是的,你应该。这是一个例子:
Order.java
@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long orderNumber;
@Version
private Long version = 0L;
@OneToMany(mappedBy="order", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<OrderLine> orderLines;
// equals() and hashcode() implementation
// getter() and setter() implementation
}
OrderLine.java
@Entity
public class OrderLine {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long lineNumber;
@ManyToOne
@JoinColumn(name="order_id", nullable=false)
private Order order;
@Version
private Long version = 0L;
// equals() and hashcode() implementation
// getter() and setter() implementation
}
最后是一个更新示例:
public boolean update(Order order, long orderLineId, OrderLine updatedOrderLine) {
if(order == null || updatedOrderLine == null)
return false;
if(order.getOrderLines() == null)
return false;
Optional<OrderLine> optTargetOrderLine = order.getOrderLines().stream()
.filter(orderline -> orderLine.getLineNumber() == orderLineId).findFirst();
if(!optTargetOrderLine.isPresent())
return false;
OrderLine targetOrderLine = optTargetOrderLine.get();
// now implement the update function
boolean status = update(targetOrderLine, updatedOrderLine);
// if status is true, you also have to call save() on your OrderRepository
return status;
}