[java] Data was not saved: object references an unsaved transient instance - save the transient instance before flushing

I have a database with two tables User and Country. I want to relationship where many user can belong to one county. I implement this using hibernate using the following model classes:

@Entity (name = "user")
public class User {

   @Id @GeneratedValue (strategy = GenerationType.IDENTITY)
    private int userId;
    private String username;
    private String password;

   @ManyToOne ()
   @JoinColumn (name = "countryId")
   private Country country;

    //Getter & Setter
 }


@Entity (name = "country")
public class Country {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int countryId;
    private String countryName;
   //Getter & Setter
}

When I try to save the user object I get the following exception:

  org.hibernate.HibernateException: Data was not saved: object references an unsaved transient instance - save the transient instance before flushing: com.kyrogaming.models.Country

How can I fix the problem?

This question is related to java hibernate

The answer is


I had the same problem. In my case it arises, because the lookup-table "country" has an existing record with countryId==0 and a primitive primary key and I try to save a User with a countryID==0. Change the primary key of country to Integer. Now Hibernate can identify new records.

For the recommendation of using wrapper classes as primary key see this stackoverflow question


Well if you have given

@ManyToOne ()
   @JoinColumn (name = "countryId")
   private Country country;

then object of that class i mean Country need to be save first.

because it will only allow User to get saved into the database if there is key available for the Country of that user for the same. means it will allow user to be saved if and only if that country is exist into the Country table.

So for that you need to save that Country first into the table.


It should be CascadeType.Merge, in that case it will update if the record already exists.


Looks like Users that are added in your Country object, are not already present in the DB. You need to use cascade to make sure that when Country is persisted, all User which are not there in data but are associated with Country also get persisted.

Below code should help:

@ManyToOne (cascade = CascadeType.ALL)
   @JoinColumn (name = "countryId")
   private Country country;

You can't save things to Hibernate until you've also told Hibernate about all the other objects referenced by this newly saved object. So in this case, you're telling Hibernate about a User, but haven't told it about the Country.

You can solve problems like this in two ways.

Manually

Call session.save(country) before you save the User.

CascadeType

You can specify to Hibernate that this relationship should propagate some operations using CascadeType. In this case CascadeType.PERSIST would do the job, as would CascadeType.ALL.

Referencing existing countries

Based on your response to @zerocool though, you have a second problem, which is that when you have two User objects with the same Country, you are not making sure it's the same Country. To do this, you have to get the appropriate Country from the database, set it on the new user, and then save the User. Then, both of your User objects will refer to the same Country, not just two Country instances that happen to have the same name. Review the Criteria API as one way of fetching existing instances.


It is because of CASCADE TYPE

if you put

@OneToOne(cascade=CascadeType.ALL)

You can just save your object like this

user.setCountry(country);
session.save(user)

but if you put

 @OneToOne(cascade={    
            CascadeType.PERSIST,
            CascadeType.REFRESH,
            ...
})

You need to save your object like this

user.setCountry(country);
session.save(country)
session.save(user)

To add my 2 cents, I got this same issue when I m accidentally sending null as the ID. Below code depicts my scenario (and anyway OP didn't mention any specific scenario).

Employee emp = new Employee();
emp.setDept(new Dept(deptId)); // -----> when deptId PKID is null, same error will be thrown
// calls to other setters...
em.persist(emp);

Here I m setting the existing department id to a new employee instance without actually getting the department entity first, as I don't want to another select query to fire.

In some scenarios, deptId PKID is coming as null from calling method and I m getting the same error.

So, watch for null values for PK ID

Same answer given here