使用EntityListener级联修改实体 [英] Modify entity with EntityListener on cascade

查看:185
本文介绍了使用EntityListener级联修改实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个数据库,其中一个实体(比如User)有一个实体列表(比如List)。作为一项要求,我必须对列表中的实体进行非规范化处理:

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

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

当我添加新的元素到列表中,我必须在事务上增加相应的计数器。

我尝试使用EntityListener来完成此操作:

  class MyBrokenEntityListener {
@PostPersist $ b $ public void incrementCounter(友谊友谊){
friendship.getUser1()。incrementFriendsCount();


正确调用实体监听器,并且在调试过程中我可以看到它正确地修改了实体。但是,Hibernate不向数据库发送UPDATE查询,只发送INSERT查询(对应于友谊实体)。

我在EntityListener上尝试了不同的事件,但它确实似乎没有工作。



我想这里发生的是实体监听器是由用户的更新触发的。然后它识别用户的所有脏属性,其中仅包含List。因此它对用户没有任何关系,只需要插入友谊。然后它将操作级联到友谊。实体监听器被调用,它修改用户,但此时Hibernate已经确定它不必担心用户,因此它不会更新用户。



<如果是这样,我该如何正确实现这一目标?



谢谢,
Bruno

解决方案


我在EntityListener上尝试过不同的事件,但似乎没有

从我所看到的 User 之间的一对多关联c $ c>和友谊是双向的,但您的映射不会反映这一点。那么你能先修正你的映射吗?像这样:

  @Entity 
public class User1 {
@Id @GeneratedValue
私人长ID;

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

public int friendsCount;

//省略getter,setter以简化

public void incrementFriendsCount(){
friendsCount ++;
}

public void addToFriends(友谊朋友){
this.getFriends()。add(friend);
friend.setUser1(this);


$ / code $ / pre
$ b $ p值得注意的变化


  • 我在关联的非拥有端添加了 mappedBy
  • 添加友谊


时,我添加了一个方便的方法来正确设置链接的两侧


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

您的 MyBrokenEntityListener 侦听器适用于我,我无法重现使用上面的固定映射问题:Hibernate确实在Listener调用之后检测到 User 实例是陈旧的,并且它确实触发了一个UPDATE。以下测试方法(在事务内部运行)通过:

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

友谊friend2 =新友谊();
user.addToFriends(friend2);
em.flush();

em.clear(); //这样我们就可以从db
user = em.find(User1.class,user.getId())重新加载托管用户;
assertEquals(2,user.getFriendsCount());
}


I have a database in which an entity (say, User) has a list of entities (say, List). As a requirement, I must have a denormalized count of the entities on the list:

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

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

When I add a new element to the list, I must, transactionally, increase the corresponding counter.

I tried to do so using an EntityListener:

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

The entity listener is being correctly called, and while debugging I can see that it correctly modifies the entity. However, Hibernate sends no UPDATE query to the database, only the INSERT query (corresponding to the Friendship entity).

I have tried different events on the EntityListener, but it does not seem to work.

What I suppose is happening here is that the entity listener is triggered by an update to the a User. It then identifies all the dirty properties of the user, which consist of the List alone. Therefore it has nothing to do about the User, it has only to insert a Friendship. It then cascades the operation to the Friendship. The entity listener is called, it modifies the user, but at this time Hibernate has already determined that it had not to worry about the user, therefore it does not update the user.

Is this reasoning correct?

If so, how can I properly achieve this?

Thanks, Bruno

解决方案

I have tried different events on the EntityListener, but it does not seem to work.

From what I can see, the one-to-many association between User and Friendship is bidirectional but your mapping doesn't reflect this. So could you fix your mapping first? Something like this:

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

Notable changes:

  • I've added a mappedBy on the non owning side of the association
  • I've added a convenient method to set both sides of the link correctly when adding a Friendship

The entity listener is called, it modifies the user, but at this time Hibernate has already determined that it had not to worry about the user, therefore it does not update the user.

Your MyBrokenEntityListener listener works for me, I couldn't reproduce the issue using the above fixed mapping: Hibernate does detect that User instance is stale after the Listener invocation and it does trigger an UPDATE. The following test method (running inside a transaction) passes:

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

这篇关于使用EntityListener级联修改实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆