06 - Query - many to one, one to many (based on springboot2.0.3 + MySQL 5.7)

Reprint please indicate Original: https://me.csdn.net/jxysgzs

1, Necessary foreword

In this article, we will talk about many to one and one to many queries in the query. The usage method in spring datajpa is very simple. It only needs one annotation to use. I believe you can understand it easily.

This tutorial continues to use the small Dome written in the previous article

2, Create a role class

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import com.fasterxml.jackson.annotation.JsonIgnore;

import javax.persistence.JoinColumn;
/**
 * @Auther:http://www.jxysgzs.cn
 * @Date:2020/2/1
 * @Description:cn.jxysgzs.springdatajpa.pojo
 * @Version:1.0
 */
/**
 * Role classes
 *
 * @author a2417
 *
 */
@Entity
@Table(name="t_role")
public class Role implements Serializable {

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

    public Integer getRoleId() {
        return roleId;
    }

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

    public String getRoleName() {
        return roleName;
    }

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

}  

This is no different from when we create the Users class. For the convenience of demonstration, we only write two fields, one is the primary key and the other is the role name.

Users and roles are two of the most important three links in the permission model. These two happen to be many to one and one to many. We assume that a user can only correspond to one role, and one role can be used by many objects.

3, Many to one

1. Modify Users class

import javax.persistence.*;

/**
 * User class. Used to map to data users table
 * @Date:2020/1/28
 * @Description:cn.jxysgzs.springdatajpa.pojo
 * @Version:1.0
 */
@Entity
@Table(name="t_users")
public class Users {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="userId")
    private int userId;
    @Column(name="userName")
    private String userName;
    @Column(name="userPwd")
    private String userPwd;

    @ManyToOne(cascade=CascadeType.PERSIST)
    private Role role;

    public Role getRole() {
        return role;
    }

    public void setRole(Role role) {
        this.role = role;
    }

    public int getUserId() {
        return userId;
    }

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

    public String getUserName() {
        return userName;
    }

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

    public String getUserPwd() {
        return userPwd;
    }

    public void setUserPwd(String userPwd) {
        this.userPwd = userPwd;
    }

    @Override
    public String toString() {
        return "Users{" +
                "userId=" + userId +
                ", userName='" + userName + '\'' +
                ", userPwd='" + userPwd + '\'' +
                '}';
    }
}

  1. A new Role object property is added to store the corresponding unique Role. The variable does not need to be declared with @ Column(name =);
  2. @ManyToOne(cascade=CascadeType.PERSIST), as the name implies, is used for annotation of many to one relationship model. This annotation only needs to be added to the corresponding attribute.
  3. @The cascade parameter in the ManyToOne annotation gives him permission to perform all kinds of associated operations. For example, when we need to query, we need to find and inject the Role object directly, so we need to save the operation. Here are some explanations for the parameters found on the network:
  • CascadeType.PERSIST: cascaded persistence (save) operation (when the owner entity is persisted, all relevant data of the entity will also be persisted.)
  • Cascade type.remove: cascade delete operation. When you delete the current entity, the entities that have a mapping relationship with it will also be deleted.
  • CascadeType.MERGE: cascading update (merge) operations. When the data in Student changes, the data in Course will be updated accordingly.
  • CascadeType.DETACH: cascade de tube / free operation. If you want to delete an entity, but it has a foreign key that cannot be deleted, you need this cascading permission. It will disassociate all related foreign key associations.
  • Cascade type.refresh: cascade refresh operation
  • CascadeType.ALL: has all the above cascading operation permissions.

After saying so much, you should be able to understand it. If you don't understand it, then look down on the effect and review it here. Maybe you will understand it.

2. Start the project and modify the database

Start the project and check the database after the project is started.
At this time, there should be two tables in the data, one is the previous table t'u users, and the other is the t'u role that JPA just generated for us.

As you can see here, JPA automatically generates a role? Role? ID for us
This is where the primary key in the role table is stored, that is, roleId.

Here we need to prepare some data to show you.

3. Add three roles to the "t" role table: masses, administrators, and group leaders

4. Modify the modification we created before in the startup class. Add a Role object. The data of the Role object needs to be consistent with the data in the database.

@SpringBootApplication
@RestController
public class SpringdatajpaApplication {
    @Autowired
    private UsersJpaDao usersJpaDao;

    public static void main(String[] args) {
        SpringApplication.run(SpringdatajpaApplication.class, args);
    }

    /**
     * Newly added
     * @param userName
     * @param userPwd
     * @return
     */
    @GetMapping("/insertUser")
    public Users insertUser(@RequestParam("userName")String userName,@RequestParam("userPwd")String userPwd){
        Users users=new Users();
        users.setUserName(userName);
        users.setUserPwd(userPwd);
        return this.usersJpaDao.save(users);
    }

    /**
     * modify
     * @param userId
     * @param userName
     * @param userPwd
     * @return
     */
    @GetMapping("/updateUser")
    public Users updateUser(@RequestParam("userId")Integer userId,@RequestParam("userName")String userName,@RequestParam("userPwd")String userPwd){
        Users users=new Users();
        users.setUserName(userName);
        users.setUserPwd(userPwd);
        users.setUserId(userId);
        Role role=new Role();
        role.setRoleId(1);
        role.setRoleName("Masses");
        users.setRole(role);
        return this.usersJpaDao.save(users);
    }

    /**
     * delete
     * @param userId
     * @return
     */
    @GetMapping("/deleteUser")
    public String  deleteUser(@RequestParam("userId")Integer userId){
        this.usersJpaDao.deleteById(userId);
        return "Delete successful";
    }
}

5. Start the project and modify the user

Browser input after project launch:

http://localhost:8080/updateUser?userName=zhaoliu&userPwd=666666&userId=1

As you can see, the query ability of the save() method has triggered the associated query, and all the data in the role object has appeared. We can also query by ourselves. What happened in the database is briefly introduced outside here?

The T? Role table will not change

The first data modified in the t'users table is added with the primary key corresponding to the crowd in the t'role table


Careful students can find that the Role object we added in the code is the data existing in the T & U Role table. What if it doesn't exist?

Here I can tell you that you will report an error. This is what I tried by myself. If you want to try, you can do it yourself. Just change the data in the Role object at will, and I will not take you to detour.

6. Let's check and see if many to one relationship will appear

Browser input:

http://localhost:8080/select/selectUserNameLike?userName=i

3, One to many

1. Modify the Role.java file

package cn.jxysgzs.springdatajpa.pojo;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import com.fasterxml.jackson.annotation.JsonIgnore;

import javax.persistence.JoinColumn;
/**
 * @Auther:http://www.jxysgzs.cn
 * @Date:2020/2/1
 * @Description:cn.jxysgzs.springdatajpa.pojo
 * @Version:1.0
 */
/**
 * Role classes
 *
 * @author a2417
 *
 */
@Entity
@Table(name="t_role")
public class Role implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="roleId")
    private Integer roleId;
    @Column(name="roleName")
    private String roleName;
    @OneToMany(mappedBy="role")
    private Set<Users> usersList=new HashSet<>();

    public Set<Users> getUsersList() {
        return usersList;
    }

    public void setUsersList(Set<Users> usersList) {
        this.usersList = usersList;
    }

    public Integer getRoleId() {
        return roleId;
    }

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

    public String getRoleName() {
        return roleName;
    }

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

}

  1. The container for storing Users should use Set, which has the ability of de duplication and is also officially stipulated by JPA
  2. @One to many (mappedby = "role") as its name implies.
  3. @The mappedBy parameter in the onetoman annotation refers to the field that should point to maintain the relationship with the primary table from the table. Defines a two-way relationship between classes. If there is a one-way relationship between classes, you do not need to provide a definition. For the role class, mappedBy should point to the role attribute in the User class.
  4. Two way relationship refers to that two classes are one to many to one or many to many relationships. This is the case with our Users class and Role class.
  5. Add a knowledge: here is an annotation @ mappedBy, which also has the same function as this attribute, but this annotation will create an additional table to maintain the connection, while the @ onetoman annotation does not use the mappedBy parameter, so we use the latter.

2. Add role dao in the dao layer to operate the t'role table

package cn.jxysgzs.springdatajpa.dao;

import cn.jxysgzs.springdatajpa.pojo.Role;
import cn.jxysgzs.springdatajpa.pojo.Users;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

/**
 * @Auther:http://www.jxysgzs.cn
 * @Date:2020/2/1
 * @Description:cn.jxysgzs.springdatajpa.dao
 * @Version:1.0
 */
public interface RoleJpaDao extends JpaSpecificationExecutor<Role>, JpaRepository<Role, Integer> {
}

3. Add an interface to select controller to query table T "role by primary key

/**
 * Various queries
 * @Auther:http://www.jxysgzs.cn
 * @Date:2020/1/30
 * @Description:cn.jxysgzs.springdatajpa.controller
 * @Version:1.0
 */
@RestController
@RequestMapping("/select")
public class SelectController {

    @Autowired
    private UsersJpaDao usersJpaDao;

    @Autowired
    private RoleJpaDao roleJpaDao;

    /**
     * Primary key query
     * @return
     */
    @GetMapping("/selectUserId")
    public Users selectUserId(@RequestParam("userId")Integer userId){
        Optional<Users> users=this.usersJpaDao.findById(userId);
        return users.get();
    }

    /**
     * Custom sql query
     * Query by account password
     * @return
     */
    @GetMapping("/selectUserNameAndUserPwd")
    public Users selectUserNameAndUserPwd(@RequestParam("userName")String userName,@RequestParam("userPwd")String userPwd){
        Users users=this.usersJpaDao.findByUserNameAndUserPwd(userName,userPwd);
        return users;
    }
    /**
     * Custom sql query
     * Fuzzy query through account number
     * @return
     */
    @GetMapping("/selectUserNameLike")
    public List<Users> selectUserNameLike(@RequestParam("userName")String userName){
        List<Users> list=this.usersJpaDao.findByUserNameLike("%"+userName+"%");
        return list;
    }

    /**
     * Sort query by condition page
     * @param userName Condition user name
     * @param pageNum Page number
     * @param pageSize Number of items displayed on one page
     * @return
     */
    @GetMapping("/selectUserList")
    public Page selectUserList(@RequestParam("userName")String userName,@RequestParam("pageNum")Integer pageNum,@RequestParam("pageSize")Integer pageSize){
        Specification<Users> spec=new Specification<Users>() {
            /**
             * Anonymous Inner Class 
             * Predicate:Encapsulates a single query condition
             * Root<Users> root:Encapsulation of properties of query objects
             * CriteriaQuery<?> query:Encapsulates the information for each part of the query we want to execute
             * CriteriaBuilder cb:Constructor of the query condition. Define different query criteria
             */
            public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                //Here, we use a list to encapsulate different conditions separately, and finally combine them into one, which is beneficial to management. If there is only one condition, you can also use it
                List<Predicate> predicates = new ArrayList<>();
                if (userName!=null) {
                    //Using CD here is more like splicing. And is to add an and after SQL. Other similarities
                    //Example of query criteria: where name = 'Li Jian'
                    //Parameter 1: attribute of query criteria parameter 2: condition value
                    predicates.add(cb.and(cb.equal(root.get("userName"),userName )));
                }
                return cb.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
        //Order defines collation
        //Sort object encapsulates collation
        Sort sort=new Sort(new Sort.Order(Sort.Direction.DESC,"userId"));
        //Pageable encapsulates the paging parameters, the current page, and the number of items displayed per page. Note: its current page starts from 0.
        //PageRequest(0, 2) Page: current page. size: number of items displayed per page
        Pageable pageable=new PageRequest(pageNum-1, pageSize, sort);
        Page<Users> page=this.usersJpaDao.findAll(spec,pageable);
        return page;
    }

    /**
     * Primary key query Role
     * @return
     */
    @GetMapping("/selectRoleId")
    public Role selectRoleId(@RequestParam("roleId")Integer roleId){
        Optional<Role> role=this.roleJpaDao.findById(roleId);
        return role.get();
    }


}

4. test

Launch project, testing
Attention is coming
Browser input:

http://localhost:8080/select/selectRoleId?roleId=1

Browser printing

There is also an error notification in the console.

Why is that? This is because the two-way association we mentioned above, what is the two-way Association, said: you have me, I have you. There are many Users objects in the Role class, and each of them corresponds to a Role object, which also corresponds to many Users objects

So how do we solve this Bug?

All of this comes from the problem of two-way binding serialization. There are many solutions. Here I recommend one of my favorite

5. Modify Role class

/**
 * @Auther:http://www.jxysgzs.cn
 * @Date:2020/2/1
 * @Description:cn.jxysgzs.springdatajpa.pojo
 * @Version:1.0
 */
/**
 * Role classes
 *
 * @author a2417
 *
 */
@Entity
@Table(name="t_role")
public class Role implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="roleId")
    private Integer roleId;
    @Column(name="roleName")
    private String roleName;
    @JsonIgnoreProperties("role")
    @OneToMany(mappedBy="role")
    private Set<Users> usersList=new HashSet<>();

    public Set<Users> getUsersList() {
        return usersList;
    }

    public void setUsersList(Set<Users> usersList) {
        this.usersList = usersList;
    }

    public Integer getRoleId() {
        return roleId;
    }

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

    public String getRoleName() {
        return roleName;
    }

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

}

@The JsonIgnoreProperties("role") annotation means to ignore serialization of the role field in the following object

6. Refresh browser

Four, summary

Today, this article has a lot of content and some complexity. I hope you can digest it well. In fact, we can see that jpa is powerful. For example, we need to add new fields, modify a lot of xml files when using Mybaits, and create fields in the database by ourselves. Now an annotation is completed, and many other functions can be realized.

Today, I went out once in the middle of writing this article. I don't know if there is any mistake. I don't think it's a big problem to browse roughly. If there is any problem, please help me to give feedback. Thank you.

Published 24 original articles, won praise 0, visited 538
Private letter follow

Keywords: Java Database Attribute SQL

Added by kristianblom on Sat, 01 Feb 2020 13:15:39 +0200