我使用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,该DAO将对象保存为
@Service
@Transactional
sessionFactory.getCurrentSession().save(object);
之后,我使用 保存的 Language实体进行创建EntityX,该实体在ManyToOne关系中使用了它…
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通过code使用某些HQL查询通过查找保存的实体来重新加载它,则一切正常,但距离“好”相去甚远。
code
不幸的是,的save(...)方法org.hibernate.Session未返回保存的对象。
save(...)
org.hibernate.Session
有任何想法如何解决吗?
您是否使用单一@Transactional方法进行编码? 如果不是这样,那么问题可能出在调用服务方法之后,将提交事务并清除会话。当您尝试保存实体时,在会话中未检测到语言对象,而是将其作为临时实例进行管理并给出错误。
如果您的代码在单个事务下,您是否尝试过一个flush()保存前实体来强制Hibernate存储Language到数据库并为其分配有效的@Id标识符?
flush()
@Id
毕竟-恕我直言-如果您对实体和语言有依赖性,最好的选择是:
@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(…)方法不会返回已保存的对象,因为该对象将保持不变(引用不变),只是对象属性发生了变化(例如标记为this的对象)@Id, 例如)!
EDIT: Make an object persistent (session.save() it I mean) don’t result in a immediate insert/update; without cascade hint Hibernate look doesn’t detect dependency between EntityX and Language and doesn’t perform a sql insert of Language before saving EntityX. languageService.save(language) call doesn’t perform session.flush() because you are under same @Transactional and without session.commit() no session.flush() is performed and best option is that Language object is still marked as transient. You can do a check: extract services save code (language entityX) and put all in single @Transactional and check if Hibernate still give you error. My best option is still perform a flush() in the middle or change your mapping, no other way