当父项在同一事务中更新时,Hibernate 删除子项

Hibernate delete child when parent is getting updated in same transaction

我在我的域模型中定义了两个实体 Customer 和 SalesOrder,它们具有从客户到 salesOrder 的一对多关系。 下面的代码删除销售订单:

SalesOrder salesOrder = salesOrderRepository.findByOrderNumber(orderNumber);
if(null != salesOrder){
        Customer customer = salesOrder.getCustomer();
        customer.setCurrentCredit(customer.getCurrentCredit() - salesOrder.getTotalPrice());
Iterator<SalesOrder> iter = customer.getSalesOrders().iterator();
        while(iter.hasNext()){
            SalesOrder order = iter.next();
            if(order.getId().equals(salesOrder.getId())){
                iter.remove();
                break;
            }
        }
        customerRepository.save(customer);

但是下面的代码并没有删除销售订单。

SalesOrder salesOrder = salesOrderRepository.findByOrderNumber(orderNumber);
if(null != salesOrder){
        Customer customer = salesOrder.getCustomer();
        customer.setCurrentCredit(customer.getCurrentCredit() - salesOrder.getTotalPrice());
SalesOrder salesOrder = salesOrderRepository.findByOrderNumber(orderNumber);
if(null != salesOrder){
        Customer customer = salesOrder.getCustomer();
        customer.setCurrentCredit(customer.getCurrentCredit() - salesOrder.getTotalPrice());
        salesOrderRepository.delete(salesOrder);
        customerRepository.save(customer);

以下是域 类: Customer.java

@Entity
@Table(name = "customer", uniqueConstraints = {       @UniqueConstraint(columnNames = { "code" }) })
public class Customer extends BaseEntity {

@Column
private String code;

@Column
private String name;

@Column
private String address;

@Column
private String phone1;

@Column
private String phone2;

@Column
private Double creditLimit;

@Column
private Double currentCredit;

@OneToMany(cascade=CascadeType.ALL,mappedBy="customer",fetch=FetchType.LAZY,orphanRemoval = true)
@LazyCollection(LazyCollectionOption.FALSE)
private List<SalesOrder> salesOrders = new ArrayList<SalesOrder>();

/**
 * @return the code
 */
public String getCode() {
    return code;
}

/**
 * @param code the code to set
 */
public void setCode(String code) {
    this.code = code;
}

/**
 * @return the name
 */
public String getName() {
    return name;
}

/**
 * @param name the name to set
 */
public void setName(String name) {
    this.name = name;
}

/**
 * @return the address
 */
public String getAddress() {
    return address;
}

/**
 * @param address the address to set
 */
public void setAddress(String address) {
    this.address = address;
}

/**
 * @return the phone1
 */
public String getPhone1() {
    return phone1;
}

/**
 * @param phone1 the phone1 to set
 */
public void setPhone1(String phone1) {
    this.phone1 = phone1;
}

/**
 * @return the phone2
 */
public String getPhone2() {
    return phone2;
}

/**
 * @param phone2 the phone2 to set
 */
public void setPhone2(String phone2) {
    this.phone2 = phone2;
}

/**
 * @return the creditLimit
 */
public Double getCreditLimit() {
    return creditLimit;
}

/**
 * @param creditLimit the creditLimit to set
 */
public void setCreditLimit(Double creditLimit) {
    this.creditLimit = creditLimit;
}

/**
 * @return the currentCredit
 */
public Double getCurrentCredit() {
    return currentCredit;
}

/**
 * @param currentCredit the currentCredit to set
 */
public void setCurrentCredit(Double currentCredit) {
    this.currentCredit = currentCredit;
}

/**
 * @return the salesOrders
 */
public List<SalesOrder> getSalesOrders() {
    return salesOrders;
}

/**
 * @param salesOrders the salesOrders to set
 */
public void setSalesOrders(List<SalesOrder> salesOrders) {
    this.salesOrders = salesOrders;
}



}

SalesOrder.java

@Entity
@Table(name = "sales_order", uniqueConstraints = { @UniqueConstraint(columnNames = { "orderNumber" }) })
public class SalesOrder extends BaseEntity {

@Column
private  String orderNumber;

@ManyToOne(cascade=CascadeType.DETACH, fetch=FetchType.LAZY)
@JoinColumn(name="customer_id",referencedColumnName="id")
private Customer customer;

@Column
private Double totalPrice;

@OneToMany(cascade=CascadeType.ALL,mappedBy="salesOrder",fetch=FetchType.LAZY,orphanRemoval = true)
@LazyCollection(LazyCollectionOption.FALSE)
private List<OrderLines> orderLines= new ArrayList<OrderLines>();

/**
 * @return the orderNumber
 */
public String getOrderNumber() {
    return orderNumber;
}

/**
 * @param orderNumber the orderNumber to set
 */
public void setOrderNumber(String orderNumber) {
    this.orderNumber = orderNumber;
}

/**
 * @return the customer
 */
public Customer getCustomer() {
    return customer;
}

/**
 * @param customer the customer to set
 */
public void setCustomer(Customer customer) {
    this.customer = customer;
}

/**
 * @return the totalPrice
 */
public Double getTotalPrice() {
    return totalPrice;
}

/**
 * @param totalPrice the totalPrice to set
 */
public void setTotalPrice(Double totalPrice) {
    this.totalPrice = totalPrice;
}

/**
 * @return the orderLines
 */
public List<OrderLines> getOrderLines() {
    return orderLines;
}

/**
 * @param orderLines the orderLines to set
 */
public void setOrderLines(List<OrderLines> orderLines) {
    this.orderLines = orderLines;
}   

}

请分享你的豆子。 根据您的描述,我希望您应该有:

                @Entity
                @Table(name="CUSTOMER")
                public class Customer implements Serializable {

                    private static final long serialVersionUID = -4505027246487844609L;

                    @Id
                    private String username;

                    @OneToMany(cascade=CascadeType.ALL, orphanRemoval=true, fetch=FetchType.EAGER)
                    @Fetch(FetchMode.SUBSELECT)
                    @JoinColumn(name="ORDER_USERNAME", nullable = false)
                    private List<SalesOrder> salesOrders;

                    }

重要的部分是:

                    @OneToMany(cascade=CascadeType.ALL, orphanRemoval=true, fetch=FetchType.EAGER)

获取类型是急切的,但也可能是惰性的,没有关于您如何获取链接实体数据的详细信息。 这应该可以解决问题,因此,如果您从父客户中删除销售额,它将被删除。

确认你的bean大致是这样的结构后,我们就可以继续分析你的问题了。

UPDATE 如果 bean 的结构是这样的,那么行为的原因就很清楚了。 当您获取 "Customer" 时,您已加载相关销售的集合... 现在.. 你在另一个对象中加载链接到该客户的销售,但 object1(客户)和 object2(销售)现在完全分开了.. 结果是,当您删除 object2 时,您实际上执行了一次删除,但随后您保存了客户(其中仍然存在对您在列表对象中删除的销售的引用),它将 update/insert 所有链接到的销售基于客户 bean 的客户。

您的情况是: 将具有 Sales1 和 Sales2 的客户提取到 Object1 中 Sales1 提取到 Object2 删除 Object2,它会删除 sales1.. 这不会改变 Object1 的内容,它仍然会有一个与 sales1 和 sales2 相关联的客户 保存 Object1,您将更新客户(因为它已经存在),您将更新 sales2(因为它已经存在)并插入 sales1(因为您通过之前的删除删除了它)。 它将全部在同一个事务中干净地处理..

现在..如果你想达到你的结果,要么你"reload"(再做一个findOne或其他)删除相关销售后的bean客户,要么直接在销售集合上工作包含在客户 bean 中,以防万一从集合中删除这些对象并在完成后保存客户对象,而不涉及未链接到客户的辅助对象,这只会弄乱整个流程..

希望对您有所帮助。