Как запретить извлечение всех записей из двунаправленной коллекции ManyToMany при добавлении новой записи - PullRequest
0 голосов
/ 27 февраля 2019

Я хотел бы знать, как предотвратить извлечение всех записей из двунаправленной коллекции ManyToMany при добавлении новой записи в эту коллекцию.У меня есть сущность User, которая имеет двунаправленную связь с сущностью UserGroup.Когда я добавляю группу в сущности пользователя, она добавляет пользователя в группу, а группа пользователей является родительской.Проблема в том, что если я добавлю много групп (скажем, 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);
    }
}

Так что я вижу вконсоль, что все записи таблицы присоединения выбраны для группы, которую я повторяю в

EDITED: это код, который был выполнен, и я не уверен почему.

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=?

Ответы [ 2 ]

0 голосов
/ 27 февраля 2019

Попробуйте пользовательский запрос, чтобы повысить производительность

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

Таким образом, пользователи в каждой группе будут загружаться в одном запросе, а не в N + 1 запросах.

Изменение @ManyToMany(FetchType.EAGER) неэффективно, поскольку пользователи всегда будут загружаться с UserGroup, даже если они не используются.

Использование @EntityGraph аналогично запросу join fetch.

0 голосов
/ 27 февраля 2019

Если вам не нужно знать, какие пользователи входят в группу (отображать это в приложении), выполните однонаправленное сопоставление.Удалить Set<User> users из класса UserGroup.

В классе 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);
}
...