【问题标题】:JpaRepository won't insert many-to-many dataJpaRepository 不会插入多对多数据
【发布时间】:2015-12-09 15:20:01
【问题描述】:

我有使用 JPA 工具生成的用户实体和角色实体。 User 和 Role 具有多对多的关系。我使用以下代码插入管理员,但是,没有数据插入到 user_role 表中。我还注意到角色类有 @JoinTable 但用户类没有。有区别吗?

private void addAdmin() {
    User admin = new User();
    admin.setDisplayName("admin");

    Role role1 = new Role();
    role1.setRole("ROLE_SUPER_ADMIN");
    Role role2 = new Role();
    role2.setRole("ROLE_END_USER");
    List<Role> roles = new ArrayList<Role>();
    roles.add(role1);
    roles.add(role2);
    admin.setRoles(roles);
    userRepository.save(admin);
}

以下是我的用户类:

@Entity
@NamedQuery(name="User.findAll", query="SELECT u FROM User u")
public class User implements Serializable {
  private static final long serialVersionUID = 1L;

  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  private int id;

  @Column(name="display_name")
  private String displayName;

  //bi-directional many-to-many association to Role
  @ManyToMany(mappedBy="users")
  private List<Role> roles;
}

以下是我的角色类:

@Entity
@NamedQuery(name="Role.findAll", query="SELECT r FROM Role r")
public class Role implements Serializable {
  private static final long serialVersionUID = 1L;

  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  private int id;

  private String role;

  //bi-directional many-to-many association to User
  @ManyToMany
  @JoinTable(
    name="user_role"
    , joinColumns={
        @JoinColumn(name="role_id")
        }
    , inverseJoinColumns={
        @JoinColumn(name="user_id")
        }
    )
  private List<User> users;
}

【问题讨论】:

    标签: hibernate jpa many-to-many


    【解决方案1】:
    @Entity
    public class User {
        @ManyToMany
        private List<Role> roles;
    }
    
    @Entity
    public class Role {
        @ManyToMany
        private List<User> users;
    }
    
    public class Auth {
        User newUser = new User("username","password");
        userDao.save(newUser);
    
        Role newRole_1 = new Role("ADMIN");
        Role newRole_2 = new Role("USER");
        roleDao.save(newRole_1);
        roleDao.save(newRole_2);
    
        List<Role> roles = roleDao.findAll();
        User user = userDao.findOne(user_id);  // e.g. Long user_id = 1L;
        for (Role role : roles) {
            user.getRoles().add(role);
        }
        userDao.save(user);
    
    }
    

    如果您创建了新对象:

        User user = new User();
        Role role = new Role();
        List<Role> roles = new ArrayList<>(); 
    

    这个对象是瞬态的,Hibernate 不能使用它们。 Hibernate 使用持久对象。因此,您必须使用方法 save();找一个();找到所有();和其他。

    【讨论】:

      【解决方案2】:

      User 实体中的roles 关联是关联的反面(由mappedBy 指定)。这意味着维护关联是Role类的职责,因此要使关联更改持久,您还必须修改所有者方:

      role1.getUsers().add(admin);
      role2.getUsers().add(admin);
      

      不管怎样,总是更新双向关联的双方是一个很好的约定,这样反方的状态也能反映所有者方的变化。这就是为什么创建改变关联双方的辅助方法是一种常见做法的原因:

      @Entity
      public class User {
      
        //bi-directional many-to-many association to Role
        @ManyToMany(mappedBy="users")
        private List<Role> roles;
      
        public void addRole(Role role) {
          if (!roles.contains(role)) {
            roles.add(role);
            role.addUser(this);
          }
        }
      }
      
      @Entity
      public class Role {
      
        //bi-directional many-to-many association to User
        @ManyToMany
        @JoinTable(
          ...
          )
        private List<User> users;
      
        public void addUser(User user) {
          if (!users.contains(user)) {
            users.add(user);
            user.addRole(this);
          }
        }  
      }
      

      【讨论】:

      • 这是合理的。但是,我还有一个问题:一个角色可能有数亿用户,每次我插入一个将调用“role2.getUsers().add(user)”的新用户时。我想知道这是否有性能问题。
      • 是的,这将是一个很大的性能问题。您可以更改映射,使User 成为关系的所有者,或者您可以尝试here 中描述的其他替代方法。
      猜你喜欢
      • 2014-10-29
      • 2016-05-13
      • 2018-12-29
      • 2019-12-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-10
      • 1970-01-01
      相关资源
      最近更新 更多