【问题标题】:How to prevent retrieval of all entries from bidirectional ManyToMany collection while adding new entry添加新条目时如何防止从双向多对多集合中检索所有条目
【发布时间】:2019-07-20 15:03:43
【问题描述】:

我想知道如何防止从双向多对多集合中检索所有条目,同时将新条目添加到该集合中。 我有用户实体,它与用户组实体具有双向关系。 当我在用户实体中添加组时,它将用户添加到组中,并且用户组是父级。问题是,如果我向用户添加了很多组(比如说 20 个),那么用户也会被添加到每个组中,并且从每个组中检索所有用户(每组 100 多个)。它使事务花费大量时间并显示出明显的滞后,而我只想将 UserGroup 插入到用户的 userGroups 集合中,而无需从这些组中选择其他用户。

User.java

@ManyToMany(mappedBy = "users")
private Set<UserGroup> userGroups;

public void addGroup(UserGroup userGroup){
this.userGroups.add(userGroup);
userGroup.addUser(this);
}

UserGroup.java

@ManyToMany
@JoinTable(name = "group_users", joinColumns = @JoinColumn(name = "group_id"),
        inverseJoinColumns = @JoinColumn(name = "user_id"))
private Set<User> users;

public void addUser(User user) {
   this.users.add(user);
}

使用的方法

@Transactional
public void addGroupsToUser(UserAddGroupsCommand userAddGroupsCommand, String username) {
    User user = userRepository.findByUsername(username);
    if (user != null) {
        List<UserGroup> userGroupList = userGroupRepository.findAllById(userAddGroupsCommand.getId());
        for (UserGroup userGroup : userGroupList) {
            user.addGroup(userGroup);
        }
        userRepository.save(user);
    }
}

所以我可以在控制台中看到,为我正在迭代的组选择了所有连接表条目

已编辑:这是执行的代码,我不知道为什么。

select users0_.group_id as group_id1_0_0_, users0_.user_id as user_id2_0_0_, user1_.id as id1_7_1_ 
from group_users users0_ 
inner join User user1_ on users0_.user_id=user1_.id 
where users0_.group_id=?

【问题讨论】:

    标签: java hibernate spring-data-jpa many-to-many bidirectional-relation


    【解决方案1】:

    尝试自定义查询以获得更好的性能

    from UserGroup g left join fetch g.users where g.id in :IDS

    这样每个组中的用户将在一个查询中加载,而不是在 N+1 个查询中加载。

    更改@ManyToMany(FetchType.EAGER) 效率不高,因为用户总是会被加载到 UserGroup 中,即使在不使用时也是如此。

    使用@EntityGraphjoin fetch 查询相同。

    【讨论】:

    • 我刚刚编辑了最后一个代码sn-p。我实际上不希望在用户被添加到组后执行这部分。
    • 如果您在调用userGroupRepository.findAllById 时开始获取用户,则不会针对每个组执行。将其替换为自定义查询 from UserGroup g left join fetch g.users where g.id in :IDS
    【解决方案2】:

    如果您不需要知道组中有哪些用户(在应用程序中显示),则进行单向映射。从 UserGroup 类中删除 Set&lt;User&gt; users

    在 User 类中使用 @JoinTable 而不是 mappedBy:

    @ManyToMany
    @JoinTable(name = "group_users", 
        joinColumns = @JoinColumn(name = "user_id"),
        inverseJoinColumns = @JoinColumn(name = "group_id"))
    private Set<UserGroup> userGroups;
    
    public void addGroup(UserGroup userGroup){
        this.userGroups.add(userGroup);
    }
    

    【讨论】:

    • 亲爱的彼得。其实我需要。我在前端有一个选项可以向用户添加组。而且我还可以选择访问组并将用户添加到组。所以我猜是需要双向的。
    • 您可以随时用存储库中的查询方法替换反向。
    猜你喜欢
    • 1970-01-01
    • 2014-05-07
    • 1970-01-01
    • 2017-06-10
    • 1970-01-01
    • 2014-11-26
    • 2023-02-05
    • 2021-05-12
    • 2019-04-06
    相关资源
    最近更新 更多