尝试使用Spring-JPA中的映射保存实体时出错

时间:2015-03-15 20:03:35

标签: spring hibernate orm spring-data-jpa

我有以下实体关系:

@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已存在于数据库中。这有什么问题?

感谢。

1 个答案:

答案 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时,开发人员有责任了解拥有方是什么,并更新关系的正确方面,以便触发数据库中新关系的持久性。

级联选项也不会在相反的方向上起作用。

我希望这会更清楚。无论如何,你需要了解继续存在的概念。