【问题标题】:Error when trying to save entities with mapping in Spring-JPA尝试在 Spring-JPA 中使用映射保存实体时出错
【发布时间】:2015-03-15 20:03:34
【问题描述】:

我有以下实体关系:

@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 可以映射到多个 OrderItem,每个 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 添加为渴望,并在多对一映射上级联应该可以解决此问题。但是,即使添加了它们,我仍然会遇到问题。

ReasonCode 已存在于数据库中。这里有什么问题?

谢谢。

【问题讨论】:

  • 在 orderItem 的联合列使字段可以为空 @JoinColumn(name="reason_code_id", nullable=true)
  • @Harshal Patil 我无法设置 nullable=true。它是数据库中的非空字段。

标签: spring hibernate orm spring-data-jpa


【解决方案1】:

您正在使用两个实体 OrderItem 和 OrderInfo 之间的双向映射。
在您的示例中,owning 实体是 OrderItem。
您可以阅读这篇文章以更好地理解:
What is the "owning side" in an ORM mapping?
这里有一个带有 department as owning 方的员工/部门(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时,开发者有责任知道什么是拥有方,并更新关系的正确方以触发新关系在数据库中的持久化。

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

我希望这会让它更清楚。无论如何,您需要了解拥有方的概念才能继续。

【讨论】:

  • 谢谢,但错误表明 ReasonCode 处于瞬态。但是,我正在为每个项目设置原因代码。另外,我将订单信息保存到每个项目。我忘了添加代码。我已经更新了代码以反映这一点。
  • 那是因为 OrderItem 没有正确持久化。
  • OrderItem 没有正确持久化是什么意思?我已将 cascade=CascadeType.ALL 放在 OrderInfo 上,所以它不应该自动保留 OrderItem 吗?抱歉,我对 JPA 有点陌生,所以我不太明白你想说什么。
  • 我尝试从 OrderItem 的 reasonCode 属性中删除 nullable=false 条件。但是当我这样做时,我收到一条错误消息:“reason_code_id 列中的空值违反了非空约束”。但是,即使我在从数据库中获取原因代码后手动设置原因代码,为什么原因代码为空?
猜你喜欢
  • 2022-06-10
  • 1970-01-01
  • 1970-01-01
  • 2020-05-19
  • 2011-07-13
  • 1970-01-01
  • 1970-01-01
  • 2011-11-01
  • 2020-04-08
相关资源
最近更新 更多