1

エンティティ(ユーザーなど)がエンティティのリスト(リストなど)を持つデータベースがあります。要件として、リスト上のエンティティの非正規化された数が必要です。

@Entity
class User {
    /* ... */
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<Friendship> friends;

    public int friendsCount;
    /* ... */
}

リストに新しい要素を追加するときは、トランザクション的に、対応するカウンターを増やす必要があります。

私はEntityListenerを使用してそうしようとしました:

class MyBrokenEntityListener {
    @PostPersist
    public void incrementCounter(Friendship friendship) {
        friendship.getUser1().incrementFriendsCount();
    }
}

エンティティ リスナーは正しく呼び出されており、デバッグ中にエンティティが正しく変更されていることがわかります。ただし、Hibernate は UPDATE クエリをデータベースに送信せず、INSERT クエリのみを送信します (Friendship エンティティに対応)。

EntityListener でさまざまなイベントを試しましたが、うまくいかないようです。

ここで起こっていると思われるのは、エンティティ リスナーがユーザーへの更新によってトリガーされるということです。次に、List だけで構成されるユーザーのすべてのダーティ プロパティを識別します。したがって、ユーザーとは関係なく、フレンドシップを挿入するだけです。次に、操作をフレンドシップにカスケードします。エンティティ リスナーが呼び出され、ユーザーが変更されますが、この時点で Hibernate はユーザーを気にする必要がないと既に判断しているため、ユーザーを更新しません。

この推論は正しいですか?

もしそうなら、どうすればこれを適切に達成できますか?

ありがとう、ブルーノ

4

1 に答える 1

0

EntityListener でさまざまなイベントを試しましたが、うまくいかないようです。

私が見る限り、 と の間の 1User対多の関連付けFriendshipは双方向ですが、マッピングにはこれが反映されていません。最初にマッピングを修正していただけますか? このようなもの:

@Entity
public class User1 {
    @Id @GeneratedValue
    private Long id;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, 
               mappedBy = "user1")
    private List<Friendship> friends = new ArrayList<Friendship>();

    public int friendsCount;

    // omitting getters, setters for brevity

    public void incrementFriendsCount() {
        friendsCount++;
    }

    public void addToFriends(Friendship friend) {
        this.getFriends().add(friend);
        friend.setUser1(this);
    }
}

主な変更点:

  • mappedBy協会の非所有側にを追加しました
  • リンクを追加するときに、リンクの両側を正しく設定するための便利な方法を追加しました。Friendship

エンティティ リスナーが呼び出され、ユーザーが変更されますが、この時点で Hibernate はユーザーを気にする必要がないと既に判断しているため、ユーザーを更新しません。

あなたのMyBrokenEntityListenerリスナーは私のために働いています.上記の固定マッピングを使用して問題を再現できませんでした.HibernateはUser、リスナーの呼び出し後にインスタンスが古くなっていることを検出し、UPDATEをトリガーします. 次のテスト メソッド (トランザクション内で実行) はパスします。

@Test
public void testPostPersistInvocationOnAddFriend() {
    User1 user = new User1();
    Friendship friend1 = new Friendship();
    user.addToFriends(friend1);
    em.persist(user);
    em.flush();
    assertEquals(1, user.getFriendsCount());

    Friendship friend2 = new Friendship();
    user.addToFriends(friend2);
    em.flush();

    em.clear(); // so that we reload the managed user from the db
    user = em.find(User1.class, user.getId());
    assertEquals(2, user.getFriendsCount());
}
于 2010-08-27T05:58:40.590 に答える