object引用未保存的瞬态实例:如何刷新或返回保存的对象

我使用Spring 3.2.3和Hibernate 4.2.3和JDK 7。

我有一个简单的实体:

@Entity public class Language { @Id @GeneratedValue private long id; @Column(nullable = false, length = 3, unique = true) private String code; } 

我使用带有@Transactional注释方法的@Service注释类保存了这个实体的实例,该方法使用DAO保存实体

 sessionFactory.getCurrentSession().save(object); 

之后我使用保存的 Language实体创建EntityX ,它在ManyToOne关系中使用它…

 lang=new Language(); // ... languageService.saveLanguage(lang); e=new EntityX(); // ... e.setLanguage(lang); otherService.saveEntity(e); 

EntityX定义为……

 @Entity public class EntityX { @ManyToOne @JoinColumn(nullable = false) private Language language; // ... } 

我总是得到例外

 Exception in thread "main" org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: somepackage.Language 

我尝试在EntityX与其他post中建议的Language关系中使用一些级联定义,但它没有任何效果。

如果我通过使用一些HQL查询通过其code查找保存的Language实体来重新加载,那么一切正常,但它远离“好”。

不幸的是, org.hibernate.Sessionsave(...)方法没有返回保存的对象。

有任何想法如何解决它?

你是用单个@Transactional方法编码的吗?
如果不是问题,那么在调用service方法之后,事务将被提交并且会话被清除。 当您尝试保存实体时,在会话中未检测到语言对象并将其作为临时实例进行管理并提供错误。

如果您的代码在单个事务下,您是否在保存实体之前尝试flush()以强制Hibernate存储Language到数据库并为其分配有效的@Id entifier?

毕竟 – 恕我直言 – 如果你有实体和语言的依赖,最好的选择是:

 @ManyToOne(cascade = CascadeType.ALL) private Language language; 

并将您的代码更改为:

 e=new EntityX(); Language lang = new Language(); // ... e.setLanguage(lang); otherService.saveEntity(e); 

并且您不需要在两个步骤(语言+实体)中持久化实体; 管理语言+实体作为单个项目

PS :org.hibernate.Session的save(…)方法不会返回保存的对象,因为对象将保持不变(引用不会更改),只是对象属性发生更改(如标记为@Id ,例如)!

编辑:
使对象持久化(我的意思是session.save())不会导致立即插入/更新; 没有级联提示Hibernate外观不检测EntityX和语言之间的依赖关系,并且在保存EntityX之前不执行语言的sql插入。
languageService.save(language)调用不执行session.flush()因为你在同一个@Transactional而没有session.commit()没有执行session.flush(),最好的选择是Language对象仍被标记为transient 。
您可以进行检查:提取服务保存代码(语言entityX)并将所有内容放在单个@Transactional并检查Hibernate是否仍然给您错误。
我最好的选择仍然是在中间执行flush()或更改映射,别无他法

首先,如果code字段是主键(或者您至少将它用作Hibernate的主要ID),请指定@Id:

 @Id @GeneratedValue(generator="assigned") @Column(length = 3) private String code; 

不指定ID列可能会让Hibernate有点困惑; 虽然不引用我的话。

如果save()在此之后仍然无效,则可以使用merge()

 Language lang = new Language("XYZ"); lang = session.merge(lange);