8

私はSpring/JPA/Hibernateを初めて使いました。簡単に聞こえるかもしれませんが、現実はそうではありませんでした。私はいくつかの助けを使うことができます。

子エンティティのリストを保持する親エンティティがあります。議論を簡単にするために、これらを使用します。

@Entity
public class Parent {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;

    @OneToMany(fetch=FetchType.EAGER, cascade = CascadeType.ALL, mappedBy="parent")
    private List<Child> children= new ArrayList<Child>();

    etc...
}

@Entity
public class Child {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    private Parent parent;

    etc...
}

@Repository
public interface ParentRepository extends JpaRepository<Parent, Long> {};

ラウンド 1 では、新しい親と新しい子を作成し、子を親のリストに追加して、子に親を設定します。親を保存すると、子も保存されます。

@Transactional(propagation=Propagation.REQUIRES_NEW)
void create() {
    Parent parent = new Parent();
    Child  child  = new Child();
    parent.add(child);
    child.setParent(parent);
    parent = repository.save(parent);
}

ラウンド 2 では、新しい子を追加します。

@Transactional(propagation=Propagation.REQUIRES_NEW)
void update() {
    Parent parent = repository.findOne(parentID);
    Child newChild = new Child();
    newChild.setParent(parent);
    parent.add(newChild);
    parent = repository.save(parent);
}

ただし、今回は新しい子が永続化されることはありません。

CascadeType、@GeneratedValue GenerationType、@Transactional Propagation タイプのほぼすべてのバリエーションを試しました...

これを休止状態で追跡すると(痛い!)、ここに私が見つけたものがあります:

  • 2 回目に保存する場合、問題は 2 番目の (新しい) 子にあります。
  • 問題は、親の子リストを永続化するときに、新しい子が (まだ) EntityManager にないため、一時的であると見なされることです。
  • その結果、効果的にチェーンを null として渡され、次のようになります。
org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is
javax.persistence.RollbackException: Error while committing thetransaction
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521)
...

Caused by: javax.persistence.RollbackException: Error while committing the transaction
    at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:92)
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:512)
...

Caused by: org.hibernate.AssertionFailure: collection [null] was not processed by flush()
    at org.hibernate.engine.spi.CollectionEntry.postFlush(CollectionEntry.java:225)
...
  • 私の実際のコードでは、「子」にも子エンティティのマップがあることが関連している可能性があります。この「値」は、「一時的な」不正流用により null として渡されるものです。
  • 私は repository.saveAndFlush() を使用して、デバッグのために物事を同期させてきました。.save() だけを使用すると、 @PreUpdate EntityListener が呼び出されますが、 @PostUpdate リスナーは呼び出されません。
  • 少なくとも親を永続化する前に、子が永続化されるか、ID が与えられただけであれば、問題はないようです。しかし、それを手動で行うのも逆効果のようです。それでも、それが私が考えることができる唯一の選択肢です。

読んでくれてありがとう。どんな助けでも大歓迎です!

4

2 に答える 2

5

問題は見つかりましたが、まだ完全な解決策はありません。

まず、いくつかの追加の背景。親と子に加えて、ここで「ハウス」と呼ぶ関連クラスがありました。House には EntityListener が定義されているため、保存/更新すると、関連付けられた Parent & Child オブジェクトが作成/更新されます。したがって、親オブジェクトと子オブジェクトが作成され、リンクされ、House に戻されて永続化されるのは、House の PostPersist/PostUpdate の間です。

したがって、問題は、ハウスの取引が完了する前にこれが行われているようです。House アクティビティが完了するまで、Parent/Child アクティビティを引き抜くだけで、すべての問題が解消されました。

私が把握できる唯一のこと (もう少し掘り下げます) は、House がその時点で完全に永続化されていないため、上記の一時的な状態になるということです。

アップデート:

1 つを無知にチョークします。どうやら EntityCallback メソッドは、「EntityManager または Query メソッドを呼び出すべきではなく、他のエンティティ オブジェクトにアクセスするべきではありません」。 それは知りませんでした。これにより、別のアクティビティでエンティティの作成をどのようにトリガーする必要があるかという問題が発生します。しかし、必要に応じて別のスレッドを開始します。皆さんありがとう!

于 2013-02-26T23:52:51.370 に答える
3

あなたが示したものはすべてかなり正常に見えるので、問題はあなたが言及したそのマップにある可能性があります. Github でSpring Data JPA を使用した双方向の 1 対多の実例があります。コードまたはクローンを調べて、次のように実行できます。

git clone git://github.com/zzantozz/testbed tmp
cd tmp/spring-data
mvn -q compile exec:java -D exec.mainClass=rds.springdata.JpaBiDiOneToManyExample
于 2013-02-26T04:42:12.637 に答える