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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18293169/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 00:10:11  来源:igfitidea点击:

object references an unsaved transient instance: how to flush or return saved object

javaspringhibernate

提问by t777

I use Spring 3.2.3 and Hibernate 4.2.3 and JDK 7.

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

I have a simple entity:

我有一个简单的实体:

@Entity
public class Language {
    @Id
    @GeneratedValue
    private long id;

    @Column(nullable = false, length = 3, unique = true)
    private String code;
}

I saved an instance of this entity using a @Serviceannotated class with a @Transactionalannotated method which uses a DAO which saves the entity with

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

sessionFactory.getCurrentSession().save(object);

After that I used the savedLanguageentity for creating EntityX, which used it in an ManyToOnerelation ...

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

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

and EntityXis defined as ...

并被EntityX定义为...

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

I always get the exception

我总是得到例外

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

I try to use some cascade-definitions in EntityX's relation to Languageas suggested in other posts, but it has no effect.

我尝试按照其他帖子中的建议使用EntityX's 关系中的一些级联定义Language,但没有效果。

If I reload the saved Languageentity by finding it by its codeusing some HQL-query, then everything works fine, but that it is far away from being 'nice'.

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

Unfortunately the save(...)method(s) of org.hibernate.Sessiondoes not return the saved object.

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

Has anybody any ideas how to solve it?

有没有人有任何想法如何解决它?

采纳答案by Luca Basso Ricci

Is you code in a single @Transactionalmethod?
If not the problem can be that, after any call to service method, transaction will be commit and session cleared. When you try to save entity, language object is not detected in session and managed as transient instance and give the error.

你是用一种@Transactional方法编码吗?
如果不是,问题可能在于,在对服务方法的任何调用之后,事务将被提交并清除会话。当您尝试保存实体时,会话中未检测到语言对象并作为瞬态实例进行管理并给出错误。

In case your code is under single transaction did you try a flush()before saving entity to force Hibernate store Languageto database and assign it a valid @Identifier?

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

After all - IMHO - if you have a dependency from Entity and Language the best choice is:

毕竟 - 恕我直言 - 如果您依赖于实体和语言,最好的选择是:

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

and change your code as:

并将您的代码更改为:

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

and you don't need to persist entity in two steps (language + entity); manage language+entity as single item

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

PS: The save(...) method(s) of org.hibernate.Session does not return the saved object because the object will remain the same (reference doesn't change), just object properties changes (like the one marked this @Id, for example)!

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 @Transactionaland 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 @Transactionaland 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

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

回答by Jason C

First, if the codefield is the primary key (or you are at least using it as your primary ID for Hibernate), specify @Id:

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

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

Not specifying an ID column could be confusing Hibernate a bit; although don't quote me on that.

不指定 ID 列可能会使 Hibernate 有点混乱;虽然不要引用我的话。

If save()still doesn't work after that, you can use merge():

如果之后save()仍然不起作用,您可以使用merge()

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