代码之家  ›  专栏  ›  技术社区  ›  Bruno Reis

在级联上使用EntityListener修改实体

  •  1
  • Bruno Reis  · 技术社区  · 14 年前

    我有一个数据库,其中一个实体(比如说,用户)有一个实体列表(比如,列表)。作为要求,我必须对列表中的实体进行非规范化计数:

    @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不向数据库发送更新查询,只发送插入查询(对应于友谊实体)。

    我在EntityListener上尝试过不同的事件,但似乎不起作用。

    这个推理正确吗?

    谢谢, 布鲁诺

    1 回复  |  直到 14 年前
        1
  •  0
  •   Pascal Thivent    14 年前

    从我看来,一对多的联系 User 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
    • 我添加了一个方便的方法,在添加链接时正确设置链接的两侧 友谊

    实体侦听器被调用,它修改用户,但此时Hibernate已经确定它不必担心用户,因此它不更新用户。

    你的 MyBrokenEntityListener 用户 实例在侦听器调用后已过时,它确实会触发更新。以下测试方法(在事务内运行)通过:

    @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());
    }