为什么单向@OneToMany更新不工作



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

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

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将持久化对象图中的所有实体。为什么会出现这个异常?(我使用的GlassFish 5.1服务器与EclipseLink JPA)

提前感谢。

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不会向持久性上下文添加作为对象图一部分的新实体。例如,在updateOrders()方法中,当我尝试用新的CustomerOrder对象列表更新现有的Customer对象时,JPA不知道list中的元素还不是持久性上下文的一部分,需要添加它们。因此,我必须修改代码,首先将List添加到持久性上下文中,然后将Customer对象与新持久化的List合并。通过这样做,我不再得到异常。顺便说一下,目前所有的映射关系都是单向的,因为我没有看到任何使用双向映射的理由。然而,通过使这些映射是双向的,我能得到什么吗?

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

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

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

@ManyToOne ()
private Customer customer;

在您的Customer实体中,您应该输入mappedBy= Customer

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

order.setCustomer(customer);
我希望我理解对了,这将解决你的问题。当您提供订单的客户详细信息时,需要提供同一客户的订单详细信息。只要其中一个就足够了。

相关内容

最新更新