6

我使用 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(...)方法org.hibernate.Session不返回保存的对象。

有没有人知道如何解决它?

4

2 回答 2

5

您是否使用单一@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, 例如)!

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

于 2013-08-18T16:09:07.980 回答
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);
于 2013-08-17T22:25:22.310 回答