Leif Ericson Leif Ericson -4 years ago 83
Java Question

"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);
}
}

Answer Source

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);
}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download