Как добавить в набор сущностей при выполнении «многие ко многим» - PullRequest
0 голосов
/ 17 апреля 2020

У меня есть следующие сущности с многократным выпуском

Субъект пользователя

@Entity
@Table(name = "users")
public class User {
    ...
    @ManyToMany
    @JoinTable(
            name = "team_members",
            joinColumns = @JoinColumn(name = "team_id"),
            inverseJoinColumns = @JoinColumn(name = "user_id"))
    private Set<Team> teams;

Субъект команды

@Entity
@Table(name = "teams")
public class Team {
    ...
    @ManyToMany
    @JoinTable(
            name = "team_members",
            joinColumns = @JoinColumn(name = "user_id"),
            inverseJoinColumns = @JoinColumn(name = "team_id"))
    private Set<User> members;
}

И у меня есть этот UserService

public interface UserService {
    UserDTO getById(Integer userId);
    ...
}

Я хочу реализовать метод внутри TeamService следующим образом:

@Override
@Transactional
public TeamDTO addMemberToTeam(Integer teamId, Integer userId, User currentUser) {
    checkCurrentUserIsAdmin(currentUser);
    User user = userService.getById(userId); <-------- PROBLEM LINE
    Team team = teamRepository.findById(teamId)
            .orElseThrow(() -> new RuntimeException("No such team"));
    team.getMembers().add(user);

    return TeamDTO.fromTeam(teamRepository.save(team));
}

Проблема в том, что у меня есть служба для возврата UserDTO, как это должно быть, но для того, чтобы заставить выпуск работать Мне нужен пользователь.

Возможные решения, о которых я мог подумать:

Решение 1:

Есть другой метод в UserService, который явно возвращает пользователя, например:

User getUserById(Integer userId);

Но не будет ли это тормозить идею о том, что UserService только возвращает UserDTO. Существует ли стандартный способ сделать это и при этом следовать рекомендациям интерфейсов служб для работы с DTO.

Решение 2:

Есть другой метод в UserService, такой как:

@Override
public void addUserToTeam(Integer userId, Team team) {
    User user = userRepository.findById(userId)
            .orElseThrow(() -> new RuntimeException("No such user"));
    user.getTeams().add(team);
    team.getMembers().add(user);
    userRepository.save(user);
}

И измените метод в TeamService следующим образом:

@Override
@Transactional
public TeamDTO addMemberToTeam(Integer teamId, Integer userId, User currentUser) {
    checkCurrentUserIsAdmin(currentUser);
    Team team = teamRepository.findById(teamId)
            .orElseThrow(() -> new RuntimeException("No such team"));

    userService.addUserToTeam(userId,team); <--- THIS NEW METHOD CALL

    return TeamDTO.fromTeam(teamRepository.save(team));
}

Это кажется лучшим решением, но у меня все еще есть ощущение, что я слишком усложняю его.

Какое было бы лучшее решение в моем случае?

1 Ответ

1 голос
/ 17 апреля 2020

Если я правильно понимаю, лучшая практика, которой вы пытаетесь следовать, состоит в том, что 1 @Service владеет @Entity, поэтому вы так стараетесь не использовать userRepository непосредственно внутри TeamService.

ИМХО, DTO требуется только тогда, когда вы общаетесь с внешними сторонами, например, когда у вас есть конечная точка REST, которая возвращает UserDTO потребителю вместо того, чтобы возвращать сам @Entity. В рамках ваших собственных приложений и сервисов, я думаю, можно использовать репозитории везде, где вам это нужно, вместо того, чтобы создавать трудности для себя, создавая жесткую линию в песке.

На всякий случай, если вы все еще хотите используйте UserDTO для связи между службами и внешними сторонами, я предлагаю это.

public class UserDTO {
   ... 
   // your fields 
   ...

   @JsonIgnore
   private User userRecord;
}

Таким образом, ваши службы будут по-прежнему иметь доступ к фактическому @Entity, и когда вы вернете этот объект в API потребители не увидят этого поля.

...