非空属性引用瞬态值 - 瞬态实例必须在当前操作之前保存

Posted

技术标签:

【中文标题】非空属性引用瞬态值 - 瞬态实例必须在当前操作之前保存【英文标题】: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

任何帮助将不胜感激!

【问题讨论】:

【参考方案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 )

以上是关于非空属性引用瞬态值 - 瞬态实例必须在当前操作之前保存的主要内容,如果未能解决你的问题,请参考以下文章

NHibernate - 非空属性引用空值或瞬态值

非空属性为持久值引用空值或瞬态值

Grails - 非空属性引用空值或瞬态值

Spring 和 Hibernate 错误——非空属性引用空值或瞬态值:com.tharaka.model.Employee.designation

HIbernate - 对象引用未保存的瞬态实例 - 在刷新之前保存瞬态实例

在刷新之前保存瞬态实例,或者将属性的级联操作设置为使其自动保存的内容