Mybatis multi table query one to many

There are several relationships between tables:
	One to many
	Many to one
	one-on-one
	Many to many
 give an example:
	Users and orders are one to many
	Orders and users are many to one
		One user can place multiple orders
		Multiple orders belong to the same user

	The ID number is one to one.
		A person can only have one ID number.
		An ID number can only belong to one person.

	Between teachers and students is many to many
		A student can be taught by more than one teacher
		A teacher can hand in more than one student
 Exceptions:
	If you take out each order, it can only belong to one user.
	therefore Mybatis Just think of many to one as one to one.

This case mainly uses the simplest User and Account model to analyze the multi table relationship of Mybatis. The User is the User table and the Account is Account
Watch. A User can have multiple accounts. The specific relationship is as follows:


	Example: users and accounts
		A user can have multiple accounts
		One account can only belong to one user (multiple accounts can also belong to the same user)
	demand: 
		Query all account information, and query order user information by association.
		be careful:
		Because one account information can only be used by one user, the associated query of user information is one-to-one query from the query of account information.
		If the account information under the user is queried from the user information, it is a one to many query, because a user can have multiple accounts.
	Steps:
		1,Create two tables: user table and account table
			Make the user table and account table have a one to many relationship: you need to use foreign keys to add in the account table
		2,Establish two entity classes: user entity class and account entity class
			Let the entity classes of users and accounts reflect the one to many relationship
		3,Create two profiles
			User profile
			Account profile
		4,Implementation configuration:
			When we query the user, we can get the account information contained under the user at the same time
			When we query the account, we can get the user information of the account at the same time

One to one query (many to one)

demand
	Query all account information, and query order user information by association.
be careful:
	Because one account information can only be used by one user, the associated query of user information is one-to-one query from the query of account information.
	If the account information under the user is queried from the user information, it is a one to many query, because a user can have multiple accounts.

Method 1: use resultType to process [not recommended]

Define entity class of account information

/**
 * <p>Title: Account</p>
 * <p>Description: Entity class of account</p>
 */
public class Account implements Serializable {
    private Integer id;
    private Integer uid;
    private Double money;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getUid() {
        return uid;
    }

    public void setUid(Integer uid) {
        this.uid = uid;
    }

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account [id=" + id + ", uid=" + uid + ", money=" + money + "]";
    }
}

Writing Sql statements

When querying account information, you should also query the user information corresponding to the account.

SELECT
	account.*,
	user.username,
	user.address
FROM
	account,
	user
WHERE 
	account.uid = user.id

+----+------+-------+----------+-----------------+
| ID | UID  | MONEY | username | address         |
+----+------+-------+----------+-----------------+
|  1 |   46 |  1000 | Lao Wang     | Beijing            |
|  2 |   45 |  1000 | Zhang San     | Beijing jinyanlong      |
|  3 |   46 |  2000 | Lao Wang     | Beijing            |
+----+------+-------+----------+-----------------+

Define AccountUser class

In order to encapsulate the query results of the above SQL statements, the AccountCustomer class is defined to include both account information and user information
Therefore, we need to inherit the User class when defining the AccountUser class.

/**
 * <p>Title: AccountUser</p>
 * <p>Description: It is a subclass of account</p>
 */
public class AccountUser extends Account {

    private String username;
    private String address;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return super.toString() + "        AccountUser{" +
                "username='" + username + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

Define the persistence layer Dao interface of the layer account

/**
 * <p>Title: IAccountDao</p>
 * <p>Description: Persistent layer interface of account</p>
 */
public interface IAccountDao {
    /**
     * Query all accounts, and obtain the user name and address information of the account
     *
     * @return
     */
    List<AccountUser> findAll();
}

Define query configuration information in IAccountDao.xml file

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dao.IAccountDao">
    <!-- Configure query all operations-->
    <select id="findAll" resultType="accountuser">
        select a.*,u.username,u.address from account a,user u where a.uid =u.id;
    </select>
</mapper>

Note: because the above query results contain both account information and user information, our return value type is returnType
The value of is set to AccountUser type, so you can receive account information and user information.

Create AccountTest test class

/**
 * <p>Description: One to many account operation</p>
 */
public class AccountTest {
    private InputStream in;
    private SqlSessionFactory factory;
    private SqlSession session;
    private IAccountDao accountDao;

    @Test
    public void testFindAll() {
        //6. Perform the operation
        List<AccountUser> accountusers = accountDao.findAll();
        for (AccountUser au : accountusers) {
            System.out.println(au);
        }
    }

    @Before//Execute before test method execution
    public void init() throws Exception {
        //1. Read the configuration file
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2. Create builder object
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //3. Create SqlSession factory object
        factory = builder.build(in);
        //4. Create SqlSession object
        session = factory.openSession();
        //5. Create Dao's proxy object
        accountDao = session.getMapper(IAccountDao.class);
    }

    @After//Execute after the test method execution is completed
    public void destroy() throws Exception {
        session.commit();
        //7. Release resources
        session.close();
        in.close();
    }
}

Summary:

Define specialized po Class as the output type, where sql All fields of the query result set. This method is relatively simple.

Method 2: use the result nesting processing of resultMap

Use resultMap to define a special resultMap for mapping one-to-one query results.
Through the object-oriented (has a) relationship, we can add an object of User class to the Account class to represent which User the Account belongs to.

Modify Account class

Add the object of User class to the Account class as an attribute of the Account class.

/**
 * <p>Title: Account</p>
 * <p>Description: Entity class of account</p>
 */
public class Account implements Serializable {
    private Integer id;
    private Integer uid;
    private Double money;
    // Represents which user the current account belongs to
    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getUid() {
        return uid;
    }

    public void setUid(Integer uid) {
        this.uid = uid;
    }

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account [id=" + id + ", uid=" + uid + ", money=" + money + "]";
    }
}

Modify methods in IAccountDao interface

/**
 * <p>Title: IAccountDao</p>
 * <p>Description: Persistent layer interface of account</p>
 */
public interface IAccountDao {
    /**
     * Query all accounts, and obtain the user name and address information of the account
     *
     * @return
     */
    List<Account> findAll();
}

Note: in the second method, change the return value to Account type.
Because the Account class contains an object of User class, it can encapsulate the User information corresponding to the Account.

Redefine IAccountDao.xml file

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dao.IAccountDao">
    <!-- Establish correspondence -->
    <resultMap type="account" id="accountMap">
        <!--Manually specify the mapping relationship between fields and entity attributes
           column: Field name of the data table
           property: Attribute name of the entity
       -->
        <id column="aid" property="id"/>
        <result column="uid" property="uid"/>
        <result column="money" property="money"/>

        <!-- association:It is used to specify the attribute of the referenced entity from the table side
            property: Current entity(account)Attribute name in(private User user)
           javaType: Current entity(account)Type of property in(User)
         -->
        <association property="user" javaType="user">
            <id column="id" property="id"/>
            <result column="username" property="username"/>
            <result column="sex" property="sex"/>
            <result column="birthday" property="birthday"/>
            <result column="address" property="address"/>
        </association>
    </resultMap>
    <select id="findAll" resultMap="accountMap">
        select u.*,a.id as aid,a.uid,a.money from account a,user u where a.uid =u.id;
    </select>
</mapper>

The < resultmap > can also be configured as follows:

    <resultMap type="account" id="accountMap">
        <!--Manually specify the mapping relationship between fields and entity attributes
           column: Field name of the data table
           property: Attribute name of the entity
       -->
        <id column="aid" property="id"/>
        <id column="id" property="user.id"/>
        <result column="uid" property="uid"/>
        <result column="money" property="money"/>

        <result column="username" property="user.username"/>
        <result column="sex" property="user.sex"/>
        <result column="birthday" property="user.birthday"/>
        <result column="address" property="user.address"/>

    </resultMap>

be careful:

In the resultMap tab
Need to follow
id result association collection
Order

Add a test method to the AccountTest class

    /**
     * Test query all
     */
    @Test
    public void testFindAll() {
        List<Account> accounts = accountDao.findAll();
        for (Account account : accounts) {
            System.out.println("--------each account Information about------------");
            System.out.println(account);
            System.out.println(account.getUser());
        }
    }

test result

One to many query

Requirements:
Query all user information and user associated account information.
analysis:
The user information and his account information have a one to many relationship, and if the user does not have account information during the query process, the user information should also be queried at this time. We think that the left external connection query is more appropriate.

Writing SQL statements

SELECT
	u.*, acc.id id,
	acc.uid,
	acc.money
FROM
	user u
LEFT JOIN account acc ON u.id = acc.uid

+----+--------------+---------------------+------+-----------------+------+------+-------+
| id | username     | birthday            | sex  | address         | id   | uid  | money |
+----+--------------+---------------------+------+-----------------+------+------+-------+
| 46 | Lao Wang         | 2018-03-07 17:37:26 | male   | Beijing            |    1 |   46 |  1000 |
| 45 | Zhang San         | 2018-03-04 12:04:06 | male   | Beijing jinyanlong      |    2 |   45 |  1000 |
| 46 | Lao Wang         | 2018-03-07 17:37:26 | male   | Beijing            |    3 |   46 |  2000 |
| 41 | Lao Wang         | 2018-02-27 17:47:08 | male   | Beijing            | NULL | NULL |  NULL |
| 42 | Xiao Erwang       | 2018-03-02 15:09:37 | female   | Beijing jinyanlong      | NULL | NULL |  NULL |
| 43 | Xiao Erwang       | 2018-03-04 11:34:34 | female   | Beijing jinyanlong      | NULL | NULL |  NULL |
| 48 | Little Ma Baoli     | 2018-03-08 11:44:00 | female   | Beijing amendment        | NULL | NULL |  NULL |
+----+--------------+---------------------+------+-----------------+------+------+-------+

Add User class to list < account >

/**
 * <p>Title: User</p>
 * <p>Description: User's entity class</p>
 */
public class User implements Serializable {

    private Integer id;
    private String username;
    private String address;
    private String sex;
    private Date birthday;

    //One to many relationship mapping: the primary table entity should contain a collection reference from the table entity
    // Which accounts do you have on behalf of the current user
    private List<Account> accounts;

    public List<Account> getAccounts() {
        return accounts;
    }

    public void setAccounts(List<Account> accounts) {
        this.accounts = accounts;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", address='" + address + '\'' +
                ", sex='" + sex + '\'' +
                ", birthday=" + birthday +
                '}';
    }
}

Add query method to Dao interface of user persistence layer

/**
* Query all users and get all account information under each user at the same time
* @return
*/
List<User> findAll();

User persistence layer IUserDao mapping file

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dao.IUserDao">
    <resultMap type="user" id="userMap">
        <id column="id" property="id"></id>
        <result column="username" property="username"/>
        <result column="address" property="address"/>
        <result column="sex" property="sex"/>
        <result column="birthday" property="birthday"/>
        <!-- collection It is used to establish the corresponding relationship of set attributes in one to many
        ofType Specifies the data type of the collection element
        -->
        <collection property="accounts" ofType="account">
            <id column="aid" property="id"/>
            <result column="uid" property="uid"/>
            <result column="money" property="money"/>
        </collection>
    </resultMap>
    <!-- Configure query all operations -->
    <select id="findAll" resultMap="userMap">
        select u.*,a.id as aid ,a.uid,a.money
        from user u
        left outer join account a
        on u.id =a.uid
    </select>
</mapper>

collection
	This section defines the account information associated with the user. Represents the associated query result set
property="accList" : 
	The result set of the associated query is stored in User Object.
ofType="account" : 
	Specifies the object type in the result set of the associated query, that is List Object type in. You can use aliases or fully qualified names here.

test method

/**
 * <p>Title: UserTest</p>
 * <p>Description: One to many operation</p>
 */
public class UserTest {
    private InputStream in;
    private SqlSessionFactory factory;
    private SqlSession session;
    private IUserDao userDao;

    @Test
    public void testFindAll() {
        //6. Perform the operation
        List<User> users = userDao.findAll();
        for (User user : users) {
            System.out.println("-------Content per user---------");
            System.out.println(user);
            System.out.println(user.getAccounts());
        }
    }

    @Before//Execute before test method execution
    public void init() throws Exception {
        //1. Read the configuration file
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2. Create builder object
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //3. Create SqlSession factory object
        factory = builder.build(in);
        //4. Create SqlSession object
        session = factory.openSession();
        //5. Create Dao's proxy object
        userDao = session.getMapper(IUserDao.class);
    }

    @After//Execute after the test method execution is completed
    public void destroy() throws Exception {
        session.commit();
        //7. Release resources
        session.close();
        in.close();
    }
}

test result

Keywords: Mybatis

Added by imamferianto on Thu, 04 Nov 2021 03:23:00 +0200