"object references an unsaved transient instance" 双向一对一

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

我有一个简单的一对一关系:

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

每当我 运行 应用程序时,我都会收到以下异常:


线程异常 "main"
org.springframework.dao.InvalidDataAccessApiUsageException:
org.hibernate.TransientPropertyValueException: 对象引用了一个未保存的
mike.Person.vehicle -> mike.Vehicle;嵌套异常是
java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException:
对象引用未保存的瞬态实例 - 保存瞬态实例
冲洗前:mike.Person.vehicle -> mike.Vehicle

我尝试按两个顺序保存实体:

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

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

我也遇到了同样的异常。

我通过以下方式解决了这个问题:

  1. 使用级联。
  2. 我想 OpenSessionInView 也可以。

请问有没有更好的解决办法?也许我在做一些根本性的错误?


以下是(琐碎的)实体和 DAO:

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

我收到了这个错误,这让我很头疼,直到我弄清楚原因..就像它说的

object references an unsaved transient instance   // Read it again

实际原因,你的对象 - 这里的外键映射对象指的是 table 保存主键。因此,在对包含外键的模型 class 执行操作之前,您必须对主键 table 执行操作..

如果你对上面的段落感到困惑,那么我会把它写得简短而亲切

您的外键引用的值在主键字段中不可用

通过

尝试sysout外键的值
System.out.println(modelClassObject.getForeignKeyGetter().getId());

我确定它会 return 0 或在外键引用的主键字段中不可用的值。

您可以在单个事务中使用级联或保留两个实体:

@Transactional
void savePersonVehiclePair(Person person, Vehicle vehicle){
    personDao.save(person);
    vehicleDao.save(vehicle);
}

好吧,我刚遇到同样的问题,所以想分享一下我是如何处理异常的。在耐心地检查了我的 jsp 之后,我意识到我犯了一个粗心的错误: 如下面的代码片段所示,我没有将路径属性设置为 "bioData.address.lga.lgaId",而是不小心将其设置为 "bioData.address.lga.lgaName"。所以作为 lgaId 的主键没有映射到 lga 对象,所以没有办法将键映射到对象。

<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>

下面的代码是错误的代码:

<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>

现在工作正常。