我使用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;
}
我使用带有@Service
注释方法的@Transactional
带注释的类保存了此实体的实例,该方法使用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
与Language
的关系中使用一些级联定义,但它没有效果。
如果我通过Language
使用一些HQL查询找到它来重新加载已保存的code
实体,那么一切正常,但它远离'好'。
不幸的是save(...)
的{{1}}方法没有返回保存的对象。
有任何想法如何解决它?
答案 0 :(得分:5)
您使用单@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(),最好的选择是语言对象仍然是标记为瞬态
您可以进行检查:提取服务保存代码(语言entityX)并将所有内容放在单@Transactional
中并检查Hibernate是否仍然给您错误。
我最好的选择仍然是在中间执行flush()或改变你的映射,没有其他方式
答案 1 :(得分:2)
首先,如果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);