Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"object references an unsaved transient instance" in bidirectional one-to-one

I have a simple one-to-one relation:

  • Separate DAO for each entity.
  • Transactions are managed by Spring.
 PersonDao personDao = ctx.getBean(PersonDao.class, "personDaoImpl");
 VehicleDao vehicleDao = ctx.getBean(VehicleDao.class, "vehicleDaoImpl");

 Vehicle vehicle = new Vehicle("Audi");
 Person person = new Person("Mike");

 vehicle.setPerson(person);
 person.setVehicle(vehicle); 

 personDao.save(person);
 vehicleDao.save(vehicle);

Whenever I run the application I get the following exception:


Exception in thread "main"
org.springframework.dao.InvalidDataAccessApiUsageException:
org.hibernate.TransientPropertyValueException: object references an unsaved
mike.Person.vehicle -> mike.Vehicle; nested exception is
java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException:
object references an unsaved transient instance - save the transient instance
before flushing : mike.Person.vehicle -> mike.Vehicle

I tried saving the entities in both orders:

personDao.save(person);
vehicleDao.save(vehicle);

and

vehicleDao.save(vehicle);
personDao.save(person);

and I get the same exception.

I was able to solve this by:

  1. Using cascading.
  2. I guess that OpenSessionInView would also work.

The question is if are there any better solutions? Maybe I'm doing something fundamentally wrong?


Here are the (trivial) entities and DAOs:

@Entity
public class Person {
    @Id @GeneratedValue
    private int id;
    private String name;
    @OneToOne
    private Vehicle vehicle;

    /* getters, setters, constructors */
}

--

@Entity
public class Vehicle {
    @Id @GeneratedValue
    private int id;
    private String name;
    @OneToOne
    private Person person;

    /* getters, setters, constructors */
}

--

@Repository
public class PersonDaoImpl implements PersonDao {

    @PersistenceContext
    private EntityManager em;

    @Transactional
    public void save(Person p) {
        em.persist(p);
    }
}

--

@Repository
public class VehicleDaoImpl implements VehicleDao {

    @PersistenceContext
    private EntityManager em;

    @Transactional
    public void save(Vehicle v) {
        em.persist(v);
    }
}
like image 793
Ori Popowski Avatar asked Mar 17 '23 03:03

Ori Popowski


2 Answers

I got this error, it was a big headache until I figured out why.. Like it's saying

object references an unsaved transient instance   // Read it again

Actual reason, your object - here foreign key mapping object is refering to a value which not available (not available in the table at time of doing dao operation) in the primary key field of the table which holds the primary key. So you've to perform operation on primary key table before performing operation on model class which holds the foreign key..

If you get confused by above paragraph, then I'll make it short and sweet

Your foreign key is referring a value which is not available in the primary key field

Try sysout the foreign key's value by

System.out.println(modelClassObject.getForeignKeyGetter().getId());

I'm sure it'll return either 0 or a value which is not available in the primary key field which the foreign key is referring.

like image 112
The Coder Avatar answered Apr 27 '23 09:04

The Coder


You can use cascading or persist both entities in a single transaction:

@Transactional
void savePersonVehiclePair(Person person, Vehicle vehicle){
    personDao.save(person);
    vehicleDao.save(vehicle);
}
like image 36
duckstep Avatar answered Apr 27 '23 10:04

duckstep