Ori Popowski
Ori Popowski

Reputation: 10672

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

I have a simple one-to-one relation:

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

Upvotes: 4

Views: 23689

Answers (3)

Domkat B Stephen
Domkat B Stephen

Reputation: 21

well, i just faced the same issue and so want to share how i went about the exception. After patiently going through my jsp, I realized i made a careless mistake: instead of setting the path attribute to "bioData.address.lga.lgaId" as shown in the code snippet below, i had carelessly set it to "bioData.address.lga.lgaName". so the primary key which was the lgaId wasn't mapped to the lga object, so there was no way for the key to be mapped to the object.

<form:select path="bioData.address.lga.lgaId" id="title" required="required" class="form-control col-md-7 col-xs-12">

                                                 <c:forEach items="${lgaList}" var="lga">
                                                    <form:option value="${lga.lgaId }"><c:out value="${lga.name}"/></form:option>
                                                </c:forEach>

                                            </form:select>

the code below was the wrong code:

<form:select path="bioData.address.lga.lgaName" id="title" required="required" class="form-control col-md-7 col-xs-12">

                                                 <c:forEach items="${lgaList}" var="lga">
                                                    <form:option value="${lga.lgaId }"><c:out value="${lga.name}"/></form:option>
                                                </c:forEach>

                                            </form:select>

it is now working fine.

Upvotes: 0

The Coder
The Coder

Reputation: 2632

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.

Upvotes: 4

duckstep
duckstep

Reputation: 1138

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

Upvotes: 3

Related Questions