Exception in thread "main" org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: org.pojo.Group
at org.hibernate.engine.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:219)
at org.hibernate.type.EntityType.getIdentifier(EntityType.java:397)
at org.hibernate.type.ManyToOneType.isDirty(ManyToOneType.java:242)
at org.hibernate.type.TypeFactory.findDirty(TypeFactory.java:597)
at org.hibernate.persister.entity.AbstractEntityPersister.findDirty(AbstractEntityPersister.java:3123)
at org.hibernate.event.def.DefaultFlushEntityEventListener.dirtyCheck(DefaultFlushEntityEventListener.java:479)
at org.hibernate.event.def.DefaultFlushEntityEventListener.isUpdateNecessary(DefaultFlushEntityEventListener.java:204)
at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:127)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:196)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:76)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:26)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at org.control.AccountTest.main(AccountTest.java:37)
說到這個例外的問題,看第一行就大概明瞭了
object references an unsaved transient instance
看到這個大致上的可能情況就是 "處於持久狀態的物件不能引用(reference)暫態物件(transition)"
他的理由很簡單 一個受 session 控管的物件根本無法參照到一個處於暫態的物件
因為處於暫態的物件不可能會在資料庫後方有對應的資料存在,故無法參照。
以下以一個多對一的例子來看一下,我僅顯示兩個物件 User(多) 和 Group(一) 的映射檔
以下以 JUint 進行這個錯誤的測試
package org.test;
import org.pojo.*;
import java.util.Date;
import org.control.HibernateUtil;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.model.Account;
import junit.framework.TestCase;
public class test extends TestCase //繼承 JUnit 的 TestCase
{
public void testManyToOne()
{
SessionFactory factory = HibernateUtil.getSessionFactory();
Session session = factory.openSession();
Transaction tx = session.beginTransaction();
//底下建立兩個 Group
Group g1 = new Group();
g1.setName("group1");
Group g2 = new Group();
g2.setName("group2");
User u;
for(int i=0;i<5;i++){
u = new User();
u.setName("Username" + i);
if(i < 3){
u.setGroup(g1);
}
else{
u.setGroup(g2);
}
session.save(u);
}
//以上程式過程中都未執行session.save(g1)&session.save(g2)
//所以這兩個物件都處於Transition狀態
tx.commit();
session.close();
}
}
以上的範例如果執行時應該會產生五個 SQL 的 INSERT 語句
Hibernate: insert into t_user (name, group_id) values (?, ?)
Hibernate: insert into t_user (name, group_id) values (?, ?)
Hibernate: insert into t_user (name, group_id) values (?, ?)
Hibernate: insert into t_user (name, group_id) values (?, ?)
Hibernate: insert into t_user (name, group_id) values (?, ?)
接著在拋出 object references an unsaved transient instance 的例外
解決問題很簡單阿 就把 g1和g2物件 save() 即可,所以在以上程式的迴圈加上
session.save(g1) 和 session.save(g2) 就好了
這時候你可能有個問題,如果我把這個 save()動作移動到迴圈後再執行呢
他最後結果還是會成功 只是會多跑幾個SQL語句 如下所示
Hibernate: insert into t_user (name, group_id) values (?, ?)
Hibernate: insert into t_user (name, group_id) values (?, ?)
Hibernate: insert into t_user (name, group_id) values (?, ?)
Hibernate: insert into t_user (name, group_id) values (?, ?)
Hibernate: insert into t_user (name, group_id) values (?, ?)
Hibernate: insert into t_group (name) values (?)
Hibernate: insert into t_group (name) values (?)
Hibernate: update t_user set name=?, group_id=? where id=?
Hibernate: update t_user set name=?, group_id=? where id=?
Hibernate: update t_user set name=?, group_id=? where id=?
Hibernate: update t_user set name=?, group_id=? where id=?
Hibernate: update t_user set name=?, group_id=? where id=?
以上顯示出了 Hibernate 會先執行t_user 的 INSERT 但是外鍵欄位則尚未賦值
待 t_Group INSERT 之後再去對 t_user 執行 UPDATE的動作 以更新外來建
沒有留言:
張貼留言