Java 对象引用未保存的临时实例:如何刷新或返回已保存的对象

Java 对象引用未保存的临时实例:如何刷新或返回已保存的对象,java,spring,hibernate,Java,Spring,Hibernate,我使用Spring3.2.3、Hibernate4.2.3和JDK7 我有一个简单的实体: @Entity public class Language { @Id @GeneratedValue private long id; @Column(nullable = false, length = 3, unique = true) private String code; } 我使用@Service注释类和@Transactional注释方法保存了该

我使用Spring3.2.3、Hibernate4.2.3和JDK7

我有一个简单的实体:

@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);
之后,我使用保存的
语言
实体来创建
EntityX
,它在一个
多通
关系中使用它

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
语言的关系中使用一些级联定义,正如在其他帖子中建议的那样,但没有效果

如果我通过使用一些HQL查询通过其
code
找到保存的
Language
实体来重新加载该实体,那么一切都可以正常工作,但它远不是“好的”

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


有人知道如何解决吗?

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

@Id 
@GeneratedValue(generator="assigned")
@Column(length = 3)
private String code;
不指定ID列可能会使Hibernate有点混乱;尽管不要引用我的话

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


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

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

毕竟-IMHO-如果您对实体和语言有依赖关系,那么最好的选择是:

@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
)的对象)

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

我最好的选择是在中间执行一个FrHuSH(或),或者改变你的映射,没有别的方式。我把代码缩短得太多了。有一个ID字段。我已将其添加到我的帖子代码中。当我使用merge而不是save时,我遇到了同样的问题。代码位于单个
@Transactional
方法中。服务方法也是
@Transactional
,但它们不需要新的事务,因此我假设使用现有的事务。我将语言保存为自己的语言,因为我有一个语言实体和多个EntityX,并且每个语言实体都使用相同的语言实体。请检查我的编辑,评论太长。我希望澄清,英语不是我的母语,sorryHi@LucaBassoRicci,我也有同样的问题,但我的技术不同,你能看看这个吗。。
e=new EntityX();
Language lang = new Language();
// ...
e.setLanguage(lang);
otherService.saveEntity(e);