我有以下实体关系:
@Entity
@Table(name="order_info")
public class OrderInfo{
@OneToMany(mappedBy="orderInfo",fetch=FetchType.EAGER,cascade=CascadeType.ALL)
@JsonIgnore
private List<OrderItem> orderItems;
}
@Entity
@Table(name="reason_codes")
public class ReasonCode{
//bi-directional many-to-one association to OrderItem
@JsonIgnore
@OneToMany(mappedBy="reasonCode",fetch=FetchType.EAGER,cascade=CascadeType.ALL)
private List<OrderItem> orderItems;
}
@Entity
@Table(name="order_item")
public class OrderItem{
//bi-directional many-to-one association to OrderInfo
@ManyToOne
@JoinColumn(name="order_info_id", nullable=false)
private OrderInfo orderInfo;
//bi-directional many-to-one association to ReasonCode
@ManyToOne
@JoinColumn(name="reason_code_id", nullable=false)
private ReasonCode reasonCode;
}
每个OrderInfo都有许多OrderItem,每个ReasonCode可以映射到多个OrderItems,每个OrderItem必须有1个OrderInfo和1个ReasonCode。
最后,设置所有内容的代码:
class Test{
...
List<OrderItem> orderItems = new ArrayList<OrderItem>();
for(...){
OrderItem item = new OrderItem();
ReasonCode rrCode = rcRepostory.findOne("2");
item.setReasonCode(rrCode);
orderItems.add(item);
}
OrderInfo order = CreateOrder.create(orderItems);
orderInfoRepo.save(order);
}
class CreateOrder{
public static OrderInfo create(List<OrderItem> orderItems){
OrderInfo oInfo = new OrderInfo();
oInfo. setABC(...);
for(OrderItem item : orderItems){
item.setOrderInfo(oInfo);
}
oInfo.setOrderItems(orderItems);
return oInfo;
}
}
现在,当我尝试保存orderInfo实体时,出现以下错误:
Not-null property references a transient value - transient instance must be saved before current operation : model.OrderItem.reasonCode -> model.ReasonCode
基本上,我要做的是,当我保存OrderInfo时,我也希望保存OrderItems。
从我在网上看到的很多帖子中,将fetch添加为eager,并在多对一映射上级联应解决此问题。但是,即使添加它们,我仍然会遇到这个问题。
ReasonCode已存在于数据库中。这有什么问题?
感谢。
答案 0 :(得分:1)
您正在使用两个实体OrderItem和OrderInfo之间的双向映射
在您的示例中,拥有实体是OrderItem
你可以阅读这篇文章以便更好地理解:
What is the "owning side" in an ORM mapping?
这是一个带有部门作为拥有方的员工/部门(OrderItem / OrderInfo)的示例:
http://examples.javacodegeeks.com/enterprise-java/jpa/one-to-many-bidirectional-mapping-in-jpa/
因此,如果您想继续使用映射,则应以这种方式保存OrderItem:
OrderInfo orderInfo =oiRepostory.findOne("2");
for(...){
OrderItem item = new OrderItem();
ReasonCode rrCode = rcRepostory.findOne("2");
item.setReasonCode(rrCode);
item.setOrderInfo(orderInfo);
orderItemRepo.save(item);
}
使用mappedBy,如果我们只调用orderInfo.getOrderItems()。add(orderItem),order_item中的外键将不会链接到新的orderInfo,因为这不是关系的拥有/跟踪方!
要将orderItem链接到新的orderInfo,您需要显式调用orderItem.setOrderInfo(orderInfo),因为这是关系的拥有方。顺便说一句,你正在使用item.setReasonCode(rrCode);
使用mappedBy时,开发人员有责任了解拥有方是什么,并更新关系的正确方面,以便触发数据库中新关系的持久性。
级联选项也不会在相反的方向上起作用。
我希望这会更清楚。无论如何,你需要了解继续存在的概念。