【问题标题】:Not-null property references a transient value - transient instance must be saved before current operation非空属性引用瞬态值 - 瞬态实例必须在当前操作之前保存
【发布时间】:2013-10-05 03:20:26
【问题描述】:

我有 2 个域模型和一个 Spring REST 控制器,如下所示:

@Entity
public class Customer{

@Id
private Long id;

@OneToOne(fetch = FetchType.EAGER)
@JoinColumn(name="COUNTRY_ID", nullable=false)
private Country country;

// other stuff with getters/setters

}

@Entity
public class Country{

@Id
@Column(name="COUNTRY_ID")
private Integer id;

// other stuff with getters/setters

}

Spring REST 控制器:

@Controller
@RequestMapping("/shop/services/customers")
public class CustomerRESTController {

   /**
    * Create new customer
    */
    @RequestMapping( method=RequestMethod.POST)
    @ResponseStatus(HttpStatus.CREATED)
    @ResponseBody
    public com.salesmanager.web.entity.customer.Customer createCustomer(@Valid @RequestBody   Customer customer, Model model, HttpServletRequest request, HttpServletResponse response) throws Exception {

        customerService.saveOrUpdate(customer);

        return customer;
    }

    // other stuff
}

我正在尝试使用以下 JSON 作为正文调用以上 REST 服务:

{
    "firstname": "Tapas",
    "lastname": "Jena",
    "city": "Hyderabad",
    "country": "1"
}

国家/地区代码 1 已在国家/地区表中。问题是当我调用此服务时出现以下错误:

org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation: com.test.model.Customer.country -> com.test.model.Country; nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation: com.test.model.Customer.country -> com.test.model.Country

任何帮助将不胜感激!

【问题讨论】:

    标签: java json spring hibernate rest


    【解决方案1】:

    我遇到了完全相同的问题。解决方案似乎是这样发送 JSON:

    {
      "firstname": "Tapas",
      "lastname": "Jena",
      "city": "Hyderabad",
      "country": {"id":"1"}
    }
    

    我猜@RequestBody 尝试映射实体而不是单个字段,因为 Customer 实例正在引用 Country 实例。

    (我有类似的两个实体,已加入。在数据库中,已创建引用实体(在您的情况下为国家)的记录,但使用 json 的实体创建(在您的情况下为客户)提供了相同的错误消息。对我来说 CascadeType.ALL 没有帮助,但 JSON 中的上述书面更改解决了问题。对于进一步的配置当然可以考虑 CascadeType。)

    【讨论】:

      【解决方案2】:

      我遇到了同样的错误,这就是我解决它的方法:

      第一个实体:

          @Entity
          public class Person implements Serializable{
              @Id
              @GeneratedValue(strategy = GenerationType.IDENTITY)
              private int personId;
              private String name;
              private String email;
              private long phoneNumber;
              private String password;
              private String userType;
              @OneToOne(fetch = FetchType.LAZY, mappedBy = "personCustomer", cascade 
              = CascadeType.ALL)
              private Customer customer;
      

      第二个实体:

      @Entity
      public class Customer implements Serializable{
          @Id
          @GeneratedValue(strategy = GenerationType.IDENTITY)
          private int customerId;
          @OneToOne(fetch = FetchType.LAZY, optional = false, cascade = 
          CascadeType.ALL)
          @JoinColumn(name = "person_customer")
          @JsonIgnore
          private Person personCustomer;
      

      我的控制器:

      @PostMapping("/customer/registration")
          public PersonCustomer addCustomer(@RequestBody Person person)
          {
              Customer customer = new Customer(person);
              person.setCustomer(customer);
              Customer cust = customerRepo.save(customer);
              logger.info("{}", cust);
              Optional<Person> person_Cust = 
              personRepo.findById(cust.getPersonCustomer().getPersonId());
              Person personNew = person_Cust.get();
              PersonCustomer personCust = new PersonCustomer();
      
              if(cust.equals(null))
              {   
                  personCust.setStatus("FAIL");
                  personCust.setMessage("Registration failed");
                  personCust.setTimestamp(personCust.timeStamp());
              }
              personCust.setStatus("OK");
              personCust.setMessage("Registration OK");
              personCust.setTimestamp(personCust.timeStamp());
              personCust.setPerson(personNew);
      
              return personCust;
          }
      

      当我添加“person.setCustomer(customer);”后问题就解决了。 由于两个 POJO 类都有相互引用,所以我们必须在使用 JPA 存储库方法之前“设置”相互引用(customerRepo.save(customer));

      【讨论】:

        【解决方案3】:

        你应该改变:

        @OneToOne(fetch = FetchType.EAGER)
        @JoinColumn(name="COUNTRY_ID", nullable=false)
        private Country country;
        

        到:

        @OneToOne(fetch = FetchType.EAGER)
        @JoinColumn(name="COUNTRY_ID")
        private Country country;
        

        只需删除可为空的设置。

        【讨论】:

        • 您能否解释一下在这种情况下 nullable 是如何产生问题的?
        【解决方案4】:

        我遇到了类似的问题。两个实体:DocumentStatusDocumentStatus 有关系 OneToMany,它代表 Document 所具有的Status 的历史记录。 p>

        所以,在 Status 中有一个 @NotNull @ManyToOne Document 引用。

        另外,我需要知道Document的实际Status。所以,我需要另一个关系,这次是@OneToOne,也是@NotNull,在Document中。

        问题是:如果两个实体都有一个@NotNull 对另一个实体的引用,我如何才能在第一次持久化这两个实体?

        解决方案是:从 actualStatus 引用中删除 @NotNull 引用。这样,它就能够持久化这两个实体。

        【讨论】:

        • 这并不能真正回答问题。如果您有其他问题,可以点击 进行提问。一旦你有足够的reputation,你也可以add a bounty 来引起对这个问题的更多关注。
        • 我为我的问题提出了一个类似的解决方案。与新问题无关。
        【解决方案5】:

        试着把 CascadeType.ALL

        @OneToOne(fetch = FetchType.EAGER,cascade=CascadeType.ALL)
        @JoinColumn(name="COUNTRY_ID", nullable=false) 
        
        private Country country;
        

        【讨论】:

        • 好吧,那就做一件事。您的客户对象具有 ID 为 1 的国家/地区对象。但该国家/地区对象未处于持久状态。首先通过发送国家 ID 获取国家对象。将从数据库中检索到的国家对象设置为客户对象。然后保存客户对象。希望这次不会出错。
        • 奇怪的是,CascadeType.ALL 对我有用,而这不起作用:@ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH })
        猜你喜欢
        • 2015-12-24
        • 2021-03-03
        • 2019-11-02
        • 1970-01-01
        • 1970-01-01
        • 2012-11-08
        相关资源
        最近更新 更多