繁体   English   中英

为什么单向@OneToMany 更新不起作用

[英]Why unidirectional @OneToMany update is not working

我对 JPA 和 ORM 概念完全陌生,所以我希望有人能清楚地解释我的代码可能存在什么问题。

@Entity
@Table(name = "PERSISTENCE_customer")

public class Customer implements Serializable {
    
     private static final long serialVersionUID = 1005220876458L;
     @Id
     @GeneratedValue(strategy = GenerationType.AUTO)
     private Long id;
     private String firstName;
     private String lastName;
     @OneToMany (cascade = CascadeType.ALL, orphanRemoval = true)
     private List<CustomerOrder> orders;
}
@Entity
@Table(name = "PERSISTENCE_ORDER")
public class CustomerOrder implements Serializable{
    private static final long serialVersionUID = 199102142021L;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @NotNull
    String status;
    @NotNull
    @OneToMany (cascade = CascadeType.ALL, orphanRemoval = true)
    private List<LineItem> lineItems = new ArrayList();
    @NotNull
    private String orderNumber;
    ................
    ................
}

@Entity
@Table(name = "PERSISTENCE_LINEITEM")
public class LineItem implements Serializable {
    private static final long serialVersionUID = 1991217202100959L;
     @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @NotNull
    private Integer quantity;
    @NotNull
    private Part part;
}

最初,客户实体是通过用户界面创建并成功持久化的。 后来,客户有订单,我用 CustomerOrder 更新客户如下:

private void UpdateCustomer(Customer customer) {
        FacesContext fc = FacesContext.getCurrentInstance();
        List<ShoppingCartItem> shoppingCart = getShoppingCart();
        CustomerOrder order = new CustomerOrder();
        List<CustomerOrder> orders = customer.getOrders();
        order.setLastUpdated(new Date());
        order.setOrderNumber(getInvoiceNumber());
        List<LineItem> lineItems = shoppingCart
                .stream()
                .map(e -> (new LineItem(e.getPart(), e.getQuantity())))
                .collect(Collectors.toList());
        order.setLineItems(lineItems);
        order.setStatus("Pending Shipment");
        order.setTotal(getTotal());
        orders.add(order);
        customer.setOrders(orders);
        try {
            updateOrders(customer, orders);
            fc.addMessage(null,
                    new FacesMessage("Customer order added successfuly"));
        } catch (ListServiceException e) {
            FacesMessage errMsg = new FacesMessage(FacesMessage.SEVERITY_FATAL,
                    "Error while adding customer order: ", e.getMessage());
            fc.addMessage(null, errMsg);
        }
    }
private void updateOrders(Customer cust, List<CustomerOrder> orders) throws ListServiceException {
            
        try { //em is the EntityManager injected as the field member
            if (em != null) {
                if (em.isOpen()) {
                    Customer c = getCustomer(cust.getId());
                    c.setOrders(orders);
                    em.merge(c);
                 } else {
                    logger.severe("Entity manager is closed");
            }
            else {
                logger.severe("Entity manager is NULL");
            }
        } catch (Exception e) {
            throw ThrowListServiceException.wrapException(e);
        }
    }

EntityManage 合并后,我得到以下异常。 我的印象是我不需要自己显式地保留 LineItem 和 CustomerOrder 实体。 我认为 JPA 将保留 object 图中的所有实体。 为什么我会收到此异常? (我正在使用带有 EclipseLink JPA 的 GlassFish 5.1 服务器)

提前致谢。

Internal Exception: java.sql.SQLIntegrityConstraintViolationException: Column 'ORDERS_ID'  cannot accept a NULL value.
Error Code: 30000
Call: INSERT INTO PERSISTENCE_CUSTOMER_PERSISTENCE_ORDER (orders_ID, Customer_ID) VALUES (?, ?)
    bind => [2 parameters bound]
Query: DataModifyQuery(name="orders" sql="INSERT INTO PERSISTENCE_USER_PERSISTENCE_ORDER (orders_ID, User_ID) VALUES (?, ?)")
    at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:331)
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:905)
 ...............................
.................................
Caused by: java.sql.SQLIntegrityConstraintViolationException: Column 'ORDERS_ID'  cannot accept a NULL value.

更新

使用 IDE (Netbeans) 调试器,我逐步完成了代码,正如我所预测的,在实体合并期间,JPA 不会将属于 ZA8CFDE6331BD59EB2AC96F89111C6 的新实体添加到上下文中。 例如,在 updateOrders() 方法中,当我尝试使用新的 CustomerOrder object 的列表更新现有的 Customer object 时,JPA 的列表中的元素还不需要持久化的部分并且它们不需要的部分上下文是要添加。 结果,我不得不修改我的代码,首先将 List 添加到持久化上下文中,然后将 Customer object 与新持久化的 List 合并。 通过这样做,我不再得到异常。

顺便说一句,目前,所有映射关系都是单向的,因为我没有看到任何使用双向映射的理由。 但是,通过使这些映射双向进行,我会得到什么吗?

您的 OneToMany 映射缺少连接规范或 mappedBy 值

我注意到了。 首先你应该向数据库提交新订单。然后你应该将它与用户链接。我不确定这是否解决了你的问题,但这是一个问题。你能检查一下吗?

在我看来,如果您将客户信息保存在您的 Order 实体中,它可能会解决这个问题。

@ManyToOne ()
    private Customer customer;

在您的客户实体中,您应该将mappedBy=customer作为订单字段。

之后,您可以为特定订单给客户,而不是为客户下订单。 在我看来,它将实现更好的关系映射;

order.setCustomer(customer);

我希望我理解正确,这将解决您的问题。 当您为订单提供客户详细信息时,您不需要为同一客户提供订单列表详细信息。 只有其中一个就足够了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM