'Not-null property references a transient value - transient instance must be saved before current operation
I have 2 domain models and one Spring REST Controller like below:
@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:
@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
}
I am trying to call above REST service with below JSON as body:
{
"firstname": "Tapas",
"lastname": "Jena",
"city": "Hyderabad",
"country": "1"
}
Where country code 1 is already there in Country table. The problem is when I am calling this service getting below error:
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
Any help will be appreciated!
Solution 1:[1]
Try putting CascadeType.ALL
@OneToOne(fetch = FetchType.EAGER,cascade=CascadeType.ALL)
@JoinColumn(name="COUNTRY_ID", nullable=false)
private Country country;
Solution 2:[2]
I had a similar problem. Two entities: Document and Status.
Document had a relationship OneToMany
with Status, that represented the history of Status the Document had.
So, there was a @NotNull
@ManyToOne
reference of Document inside Status.
Also, I needed to know the actual Status of Document. So, I needed another relationship, this time @OneToOne
, also @NotNull
, inside Document.
The problem was: how can I persist both entities the first time if both had a @NotNull
reference to the other?
The solution was: remove @NotNull
reference from actualStatus
reference. This way, it was able to persist both entities.
Solution 3:[3]
I had the exact same problem. The solution seems to be to send the JSON like this:
{
"firstname": "Tapas",
"lastname": "Jena",
"city": "Hyderabad",
"country": {"id":"1"}
}
I guess @RequestBody
tries to map an entity not a single field since the Customer instance is referencing a Country instance.
(I have similarly two entities, joined. In the DB, records for the referenced entity (Country in your case) were already created but the entity creation (Customer in your case) with a json, provided the same error message. For me CascadeType.ALL not helped but the above written change in the JSON solved the problem. For further config of course CascadeType can be considered.)
Solution 4:[4]
I got same error and this is how I solved it:
1st Entity:
@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;
2nd Entity:
@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;
My Controller:
@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;
}
The problem got solved when I added "person.setCustomer(customer);". As both POJO classes has each others reference, so we have to "set" each others reference before using the JPA repository method(customerRepo.save(customer));
Solution 5:[5]
Just to add an additional scenario that led me to this exact same error:
Make sure that any backward references that may exist are not null.
Specifically in my case, I was using Mapstruct
to update some fields of the entity, e.g.
MyClass newInstance = //...
MyClass dbInstance = repository.findByField(someField);
MyClassMapper.MAPPER.update(dbInstance, newInstance);
repository.save(dbInstance);
And my poor implementation of MyClassMapper
led the backward references of dbInstance
fields to be set to null
when they should be pointing back to dbInstance
.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Dmytro Plekhotkin |
Solution 2 | Dmytro Plekhotkin |
Solution 3 | |
Solution 4 | Nishchay Gupta |
Solution 5 | João Matos |