首页 > 解决方案 > 进行多对多时如何添加到一组实体

问题描述

我有以下具有多对多关系的实体

用户实体

@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,例如:

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

这似乎是一个更好的解决方案,但我仍然觉得我把它复杂化了。

在我的情况下,哪个是更好的解决方案?

标签: javaspringspring-bootspring-data-jpaspring-data

解决方案


如果我理解正确,您尝试遵循的最佳实践是 1@Service拥有 an @Entity,这就是为什么您如此努力不userRepository直接在内部使用的原因TeamService

恕我直言,DTO仅当您与外部方进行通信时才需要,例如当您有一个将 a 返回UserDTO给消费者而不是返回@Entity自身的 REST 端点时。在您自己的应用程序和服务的范围内,我认为在您需要的任何地方都可以使用存储库,而不是为自己创建一条强硬的路线而使其变得困难。

以防万一您仍想使用UserDTO来在服务之间以及与外部方进行通信,我建议这样做。

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

   @JsonIgnore
   private User userRecord;
}

这样,您的服务仍然可以访问实际@Entity,并且当您将此对象返回给 API 使用者时,他们将看不到该字段。


推荐阅读