Spring Data Project - Spring Data JPA Multi-to-Multi Association

Links to the original text: https://blog.csdn.net/BruceLiu_code/article/details/94724913

1. Example analysis

The examples we use are users and roles.
User: It means every student in our class.
Role: It refers to the identity information of our classmates.
For example, classmate A, it is my student, one of which is a student, or a child in the family, then he also has an identity is a child.
At the same time, it also has the status of students and children.
So any student may have multiple identities. At the same time, the identity of students can be possessed by many students.
So we say that the relationship between users and roles is many-to-many.

2. Establishment of Table Relations

The relationship between many-to-many tables depends on the intermediate tables, in which the relationship between user tables and intermediate tables is one-to-many, and the relationship between role tables and intermediate tables is one-to-many, as shown in the following figure:

3. Establishment of entity class relations and mapping configuration

A user can have multiple roles, so the information of multiple roles should be included in the user entity class. The code is as follows:

@Entity
@Table(name = "sys_user")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="user_id")
    private Long userId;
    @Column(name="user_name")
    private String userName;
    @Column(name="age")
    private Integer age;

    /**
     * Configuring many-to-many relationships between users and roles
     *      Configuring many-to-many mapping relationships
     *          1.Configuration of declaration table relationships
     *              @ManyToMany(targetEntity = Role.class)  //Many-to-many
     *                  targetEntity: Entity class bytecode representing the other party
     *          2.Configure the intermediate table (containing two foreign keys)
     *                @JoinTable
     *                  name : Name of intermediate table
     *                  joinColumns: Configure the foreign key of the current object in the middle table
     *                      @JoinColumn Array
     *                          name: Foreign key name
     *                          referencedColumnName: The primary key name of the reference table
     *                  inverseJoinColumns: Configure the foreign keys of each other's objects in the middle table
     */
    @ManyToMany(targetEntity = Role.class,cascade = CascadeType.ALL)
    @JoinTable(name = "sys_user_role",
            //Join Columns, the foreign key of the current object in the middle table
            joinColumns = {@JoinColumn(name = "sys_user_id",referencedColumnName = "user_id")},
            //InverseJoin Columns, the foreign key of the other object in the middle table
            inverseJoinColumns = {@JoinColumn(name = "sys_role_id",referencedColumnName = "role_id")}
    )
    private Set<Role> roles = new HashSet<>();

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Set<Role> getRoles() {
        return roles;
    }

    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }
}

A role can be assigned to more than one user, so the role entity class should contain more than one user's information. The code is as follows:

@Entity
@Table(name = "sys_role")
public class Role {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "role_id")
    private Long roleId;
    @Column(name = "role_name")
    private String roleName;

    //Configure many-to-many
    @ManyToMany(mappedBy = "roles")  //Configuring multitable relationships
    private Set<User> users = new HashSet<>();

    public Long getRoleId() {
        return roleId;
    }

    public void setRoleId(Long roleId) {
        this.roleId = roleId;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    public Set<User> getUsers() {
        return users;
    }

    public void setUsers(Set<User> users) {
        this.users = users;
    }
}

4. Annotation of Mapping

  • @ManyToMany
    Role: Used to map many-to-many relationships
    Attributes:
    Cascade: Configure cascade operations.
    fetch: Configure whether delayed loading is used.
    targetEntity: Configure the target entity class. Mapping many-to-many does not need to be written.

  • @JoinTable
    Role: Configuration for intermediate tables
    Attributes:
    nam: Configure the name of the intermediate table
    Join Columns: The foreign key field of the intermediate table associates the primary key field of the table corresponding to the current entity class
    inverseJoinColumn: The foreign key field of the intermediate table associates the primary key field of the table

  • @JoinColumn
    Function: Used to define the corresponding relationship between the primary key field and the foreign key field.
    Attributes:
    Name: Specifies the name of the foreign key field
    ReferdColumnName: Specifies the name of the primary key field that references the primary table
    Unique: is it unique? Default values are not unique
    nullable: is it allowed to be empty? Default values are allowed.
    insertable: Is insertion allowed? Default values are allowed.
    updatable: whether updates are allowed. Default values are allowed.
    Column Definition: Definition information for columns.

5. Many-to-many operations

5.1. Preservation

    /**
     * Demand:
     * 	Save users and roles
     * Requirement:
     * 	Create two users and three roles
     * 	Let user 1 have roles 1 and 2 (bidirectional)
     * 	Let User 2 have Roles 2 and 3 (bidirectional)
     *  Save users and roles
     * Questions:
     *  When saving, there will be a primary key duplication error, because it is caused by the data to be saved in the intermediate table.
     * Solution:
     * 	Let either party waive the right to maintain the affiliated relationship
     */
    @Test
    @Transactional  //Open a transaction
    @Rollback(false)//Set to no rollback
    public void test1(){
        //create object
        User u1 = new User();
        u1.setUserName("User 1");
        Role r1 = new Role();
        r1.setRoleName("Role 1");
        //Establishing Relevance Relationships
        u1.getRoles().add(r1);
        r1.getUsers().add(u1);
        //Preservation
        roleDao.save(r1);
        userDao.save(u1);
    }
   }
   
    //Test Cascade Add (Save a User while Save User's Associated Roles)
    @Test
    @Transactional
    @Rollback(false)
    public void  testCasCadeAdd() {
        User user = new User();
        user.setUserName("petty thief");

        Role role = new Role();
        role.setRoleName("java Programmer");

        //Configure user-to-role relationships to maintain 1-1 data in the intermediate table
        user.getRoles().add(role);

        //Configure the role-to-user relationship to maintain 1-1 of the data in the intermediate table
        role.getUsers().add(user);

        userDao.save(user);
    }

In many-to-many (save) systems, if two-way relations are set up, it means that both sides maintain the intermediate table and insert data into the intermediate table. The two fields of the intermediate table are used as joint primary keys. Therefore, errors are reported and the primary keys are duplicated to solve the problem of preservation failure. It is only necessary for either side to give up the right to maintain the intermediate table. It is recommended to give up on the passive side. The configuration is as follows:

    //Configure many-to-many
    @ManyToMany(mappedBy = "roles")  //Configuring multitable relationships
    private Set<User> users = new HashSet<>();

5.2. Delete

    /**
     * Case study: Delete a user with id 1 and delete his associated objects
     */
    @Test
    @Transactional
    @Rollback(false)
    public void  testCasCadeRemove() {
        //Query User No. 1
        User user = userDao.findOne(1l);
        //Delete User No. 1
        userDao.delete(user);

    }

Keywords: Java

Added by Goofan on Mon, 12 Aug 2019 15:23:58 +0300