一尘不染

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

hibernate

我使用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将对象保存为

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通过code使用某些HQL查询通过查找保存的实体来重新加载它,则一切正常,但距离“好”相去甚远。

不幸的是,的save(...)方法org.hibernate.Session未返回保存的对象。

有任何想法如何解决吗?


阅读 295

收藏
2020-06-20

共1个答案

一尘不染

您是否使用单一@Transactional方法进行编码?
如果不是这样,那么问题可能出在调用服务方法之后,将提交事务并清除会话。当您尝试保存实体时,在会话中未检测到语言对象,而是将其作为临时实例进行管理并给出错误。

如果您的代码在单个事务下,您是否尝试过一个flush()保存前实体来强制Hibernate存储Language到数据库并为其分配有效的@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

2020-06-20