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;
}

エンティティを保存するDAOを使用する注釈付きメソッドを@Service持つ注釈付きクラスを使用して、このエンティティのインスタンスを保存しました@Transactional

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

HQLクエリを使用して保存されたLanguageエンティティを見つけてリロードする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);

また、2 つのステップ (言語 + エンティティ) でエンティティを永続化する必要はありません。言語+エンティティを単一のアイテムとして管理

PS : org.hibernate.Session の save(...) メソッドは保存されたオブジェクトを返しません。これは、オブジェクトが同じまま (参照は変更されない) であるためです。@Id、 例えば)!

EDIT:
オブジェクトを永続的にします(session.save()つまり)は、すぐに挿入/更新されません。カスケード ヒントがない場合、Hibernate ルックは EntityX と Language の間の依存関係を検出せず、EntityX を保存する前に Language の SQL 挿入を実行しません。
languageService.save(language) 呼び出しは session.flush() を実行しません。これは、session.commit() を使用し@Transactionalないと session.flush() が実行されず、Language オブジェクトがまだ一時的なものとしてマークされているためです。
チェックを行うことができます: サービスの保存コード (language entityX) を抽出し、すべてを 1 つにまとめて、@TransactionalHibernate でエラーが発生するかどうかを確認します。
私の最善の選択肢は、途中で 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 に答える