简体   繁体   English

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

[英]Why unidirectional @OneToMany update is not working

I am completely new to JPA and ORM concept, so I am hoping someone can lucidly explain what might be the problem with my code.我对 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;
}

Initially, the Customer entity is created through the user interface and persisted successfully.最初,客户实体是通过用户界面创建并成功持久化的。 Later, the customer has an order and I update the Customer with CustomerOrder as follow:后来,客户有订单,我用 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);
        }
    }

Once the EntityManage merges I get the following exception. EntityManage 合并后,我得到以下异常。 I was under the impression that I don't need to explicitly persist the LineItem and CustomerOrder entities myself.我的印象是我不需要自己显式地保留 LineItem 和 CustomerOrder 实体。 I thought that the JPA will persist all the entities in the object graph.我认为 JPA 将保留 object 图中的所有实体。 Why am I getting this exception?为什么我会收到此异常? (I am using GlassFish 5.1 server with EclipseLink JPA) (我正在使用带有 EclipseLink JPA 的 GlassFish 5.1 服务器)

Thanks in advance.提前致谢。

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.

Update更新

Using the IDE (Netbeans) debugger, I stepped through the code, and as I predicted, during the entity merge the JPA does not add new entities that are part of the object graph to the persistence context. 使用 IDE (Netbeans) 调试器,我逐步完成了代码,正如我所预测的,在实体合并期间,JPA 不会将属于 ZA8CFDE6331BD59EB2AC96F89111C6 的新实体添加到上下文中。 For instance, in the updateOrders() method when I try to update the existing Customer object with a list of new CustomerOrder object, the JPA doesn't figure out that the elements in the List are not part of the persistence context yet and they need to be added. 例如,在 updateOrders() 方法中,当我尝试使用新的 CustomerOrder object 的列表更新现有的 Customer object 时,JPA 的列表中的元素还不需要持久化的部分并且它们不需要的部分上下文是要添加。 As a result, I had to modify my code to first add the List to the persistence context and then merge the Customer object with the newly persisted List. 结果,我不得不修改我的代码,首先将 List 添加到持久化上下文中,然后将 Customer object 与新持久化的 List 合并。 By doing so I no longer get the exception. 通过这样做,我不再得到异常。

By the way, at moment, all the mapping relationships are unidirectional because I didn't see any reasons to use bidirectional mapping.顺便说一句,目前,所有映射关系都是单向的,因为我没有看到任何使用双向映射的理由。 However, would I gain anything by making these mappings bidirectionals?但是,通过使这些映射双向进行,我会得到什么吗?

Your OneToMany mapping is missing join specification or mappedBy value您的 OneToMany 映射缺少连接规范或 mappedBy 值

I noticed that.我注意到了。 Firstly You should commit new order to database.Then you should link it with user.I'm not sure if this solves your problem but this is a problem.Can you check it?首先你应该向数据库提交新订单。然后你应该将它与用户链接。我不确定这是否解决了你的问题,但这是一个问题。你能检查一下吗?

In my opinion, if you keep customer information in your Order entity, it may solve this problem.在我看来,如果您将客户信息保存在您的 Order 实体中,它可能会解决这个问题。

@ManyToOne ()
    private Customer customer;

And in your Customer entity you should put mappedBy=customer for orders field.在您的客户实体中,您应该将mappedBy=customer作为订单字段。

After that, instead of giving orders for customer, you can give customer for a specific order.之后,您可以为特定订单给客户,而不是为客户下订单。 In my opinion it will achieve a better relationship mapping;在我看来,它将实现更好的关系映射;

order.setCustomer(customer);

I hope i understood it right and this will solve your problem.我希望我理解正确,这将解决您的问题。 When you give customer detail for order, you dont need to give orderlist detail for the same customer.当您为订单提供客户详细信息时,您不需要为同一客户提供订单列表详细信息。 Only one of them should be enough.只有其中一个就足够了。

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

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