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

时间:2015-06-23 09:31:54

标签: hibernate spring-data

我在我的域模型中定义了两个实体Customer和SalesOrder,其中包含从customer到salesOrder的oneToMany关系。 以下代码删除销售订单:

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;
}   

}

1 个答案:

答案 0 :(得分:2)

请分享你的豆子。 鉴于你的描述,我希望你应该:

                @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)

fetchtype非常渴望,但也可能是懒惰的,没有关于如何获取链接实体数据的详细信息。 这应该可以解决问题,因此如果从父客户中删除销售,它将被删除。

在确认您的bean大致结构如下之后,我们可以继续分析您的问题。

UPDATE 如果bean的结构如此,那么行为的原因是明确的。 当您获取“客户”时,您已加载相关销售的集合... 现在..你在另一个对象中加载一个链接到该客户的销售,但是对象1(客户)和对象2(销售)现在完全分开了.. 结果是,当您删除object2时,您实际执行了删除,但随后您保存了客户(在列表对象中仍然存在对您删除的销售的引用),它将更新/插入与客户链接的所有销售基于客户bean。

您的情况是: 将Sales1和Sales2的客户提取到Object1中 Sales1进入Object2 删除Object2,它将删除不会改变Object1内容的sales1 ..,它仍然会有一个与sales1和sales2链接的cusotmer 保存Object1,您将更新客户(因为它已经存在),您将更新sales2(因为它已经存在)并插入sales1(因为您通过之前的删除删除了它)。 它将在同一笔交易中干净利落地处理..

现在..如果你想要实现你的结果,你可以在删除相关销售后“重新加载”(做另一个findOne或其他任何)bean客户,或者直接处理客户中包含的销售集合bean,以及从集合中删除这些对象并在完成时保存客户对象,而不涉及未链接到客户的辅助对象,这只会弄乱整个流程。

希望它有所帮助。