本来想配置多对多关系(中间表),并把多对多拆分为两个一对多之后发现一个问题,在一对多时,子类保存父类时报错
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.study.hibernate.domain.TbUser
at org.hibernate.engine.internal.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:249)
at org.hibernate.type.EntityType.getIdentifier(EntityType.java:509)
at org.hibernate.type.ManyToOneType.isDirty(ManyToOneType.java:311)
at org.hibernate.type.ManyToOneType.isDirty(ManyToOneType.java:321)
at org.hibernate.type.TypeHelper.findDirty(TypeHelper.java:294)
at org.hibernate.persister.entity.AbstractEntityPersister.findDirty(AbstractEntityPersister.java:4049)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.dirtyCheck(DefaultFlushEntityEventListener.java:537)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.isUpdateNecessary(DefaultFlushEntityEventListener.java:235)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:164)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:230)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:100)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:55)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1159)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:404)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
at com.study.hibernate.operate.HibernateTest.saveTest3(HibernateTest.java:275)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
配置如下:
主表:
<hibernate-mapping>
<class name="com.study.hibernate.domain.TbUser" table="tb_user" catalog="db_hibernate" select-before-update="true">
<id name="id" column="id" type="java.lang.Long">
<generator class="native"></generator>
</id>
<property name="name" column="name" type="java.lang.String"></property>
<property name="age" column="age" type="java.lang.Long"></property>
<property name="city" column="city" type="java.lang.String"></property>
<set name="orders" cascade="save-update,delete-orphan" inverse="true">
<key column="tb_user_id"/>
<one-to-many class="com.study.hibernate.domain.Order"/>
</set>
</class>
</hibernate-mapping>
从表:
<hibernate-mapping>
<class name="com.study.hibernate.domain.Order" table="tb_order" catalog="db_hibernate">
<id name="id" column="id" type="java.lang.Long">
<generator class="native"></generator>
</id>
<property name="addr" column="addr" type="java.lang.String"></property>
<property name="totalprice" column="totalprice" type="java.lang.Long"></property>
<many-to-one name="user" class="com.study.hibernate.domain.TbUser" column="tb_user_id" />
</class>
</hibernate-mapping>
执行测试:报上面的错误
public void saveTest3(){
Configuration configuration = new Configuration().configure();
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
TbUser user = new TbUser();
user.setName("wangwu");
user.setAge(new Long(12));
user.setCity("bj");
Order order = new Order();
order.setAddr("nihao");
order.setTotalprice(new Long(200));
order.setUser(user);
session.save(order);
transaction.commit();
session.close();
sessionFactory.close();
}
原因是因为在没有保存主表的情况下保存了子表,解决办法在<many-to-one> 中加入cascade
<many-to-one name="user" cascade="all" class="com.study.hibernate.domain.TbUser" column="tb_user_id" />
问题解决,输出结果为:
Hibernate: insert into db_hibernate.tb_user (name, age, city) values (?, ?, ?)
Hibernate: insert into db_hibernate.tb_order (addr, totalprice, tb_user_id) values (?, ?, ?)