MyBatis的关联映射023.一对多3.1基本介绍

mybatis – MyBatis 3 | XML 映射器

多对一关系也是一个基本的映射关系,多对一,也可以理解为一对多。例如:

User–Pet:一个用户可以有多只宠物

Dep–Emp:一个部门有多个员工

双向的多对一关系:通过User可以查询到对应的所有Pet,反之,通过Pet也可以级联查询到对应的User信息。

多对多的关系就是在多对一的关系上拓展

3.2案例实现

映射方式:

方式1:通过配置映射文件实现多对一

方式2:通过注解的方式实现多对一

需求说明:实现级联查询,通过user的user_id可以查询到User信息和关联的所有pet信息,反之,通过pet的pet_id也可以查询到Pet信息和user的信息

先创建user表和pet表:

-- 创建user表CREATE TABLE `user`(`id` INT PRIMARY KEY AUTO_INCREMENT,`name` VARCHAR(32) NOT NULL DEFAULT '')CHARSET=utf8DESC `user`;-- 创建pet表CREATE TABLE `pet`(`id` INT PRIMARY KEY AUTO_INCREMENT,`nickname` VARCHAR(32) NOT NULL DEFAULT '',`user_id` INT,FOREIGN KEY (user_id) REFERENCES `user`(id))CHARSET=utf8

3.2.1方式一:配置方式

(1)User和Pet实体类

package com.li.entity;/** * @author 李 * @version 1.0 */public class User {    private Integer id;    private String name;    //因为一个User可以养多个宠物,mybatis使用集合体现这个关系    private List pets;        //setter、getter方法省略    //双向映射不要使用toString方法,否则会造成栈溢出错误}
package com.li.entity;/** * @author 李 * @version 1.0 */public class Pet {    private Integer id;    private String nickname;    //一个pet对应一个user对象    private User user;    //setter、getter方法省略    //双向映射不要使用toString方法,否则会造成栈溢出错误}

(2)UserMapper接口和PetMapper接口

public interface UserMapper {    //通过id获取User对象    public User getUserById(Integer id);}
public interface PetMapper {    //通过user的id获取pet对象,可能有多个因此使用集合接收    public List getPetByUserId(Integer userId);}

(3)UserMapper.xml,思路:

1)先通过user_id查询得到user信息

2)再根据user_id,查询对应的pet信息,并映射到user-List pets

多对多的映射思路和一对一的实现类似,不同的使用使用resultMap映射属性时使用的是collecting标签。

                SELECT * FROM `user` WHERE id = #{id};                                                

(4)PetMapper.xml,思路和前面大体相同

    <!--通过user的id获取pet对象,可能有多个因此使用集合接收        public List getPetByUserId(Integer userId);-->            SELECT * FROM `pet` WHERE user_id =#{userId};                                    

(5)测试getUserById()方法,通过UserId查找user对象和联系的pet信息

@Testpublic void getUserById() {    User user = userMapper.getUserById(2);    System.out.println("user信息=" + user.getId() + "-" + user.getName());    for (Pet pet : user.getPets()) {        System.out.println("宠物信息=" + pet.getId() + "-" + pet.getNickname());    }    if (sqlSession != null) {        sqlSession.close();    }}

测试结果:

(6)测试getPetByUserId()方法,通过user的id获取pet对象

@Testpublic void getPetByUserId() {    List pets = petMapper.getPetByUserId(1);    for (Pet pet : pets) {        System.out.println("UserId=" + pet.getUser().getId()                + "-PetId=" + pet.getId()                + "-PetNickName=" + pet.getNickname());    }    if (sqlSession != null) {        sqlSession.close();    }}

测试结果:

resultMap可以复用,如果有其他方法是返回的和resultMap一样的类型,可以在实现该方法时引用该resultMap。

比如PetMapper接口中新声明了一个方法:

//通过pet的id获取Pet对象,同时查询到pet对象关联的user对象public Pet getPetById(Integer id);

PerMapper.xml文件:

    SELECT * FROM `pet` where id =#{id};

3.2.2方式二:注解方式

需求说明:通过注解的方式,实现双向的级联查询。

在实际开发中推荐使用配置的方式来做

(1)User和Pet实体类不变

(2)直接在接口中,通过注解实现级联查询

UserMapperAnnotation.java

package com.li.mapper;import com.li.entity.User;import org.apache.ibatis.annotations.*;/** * @author 李 * @version 1.0 * 以注解的方式来实现多对一 */public interface UserMapperAnnotation {    //通过id获取User对象    @Select(value = "SELECT * FROM `user` WHERE id = #{id}")    @Results({            @Result(id = true, property = "id", column = "id"),            @Result(property = "name", column = "name"),            //这里对应返回List类型属性pets,使用注解的many属性            @Result(property = "pets", column = "id",                    many = @Many(select =                                  "com.li.mapper.PetMapperAnnotation.getPetByUserId"))    })    public User getUserById(Integer id);}

PetMapperAnnotation.java

package com.li.mapper;import com.li.entity.Pet;import org.apache.ibatis.annotations.*;import java.util.List;/** * @author 李 * @version 1.0 */public interface PetMapperAnnotation {    //通过user的id获取pet对象    @Select(value = "SELECT * FROM `pet` WHERE user_id =#{userId}")    //配置了id之后就可以复用PetResuleMap    @Results(id = "PetResuleMap", value = {            @Result(id = true, property = "id", column = "id"),            @Result(property = "nickname", column = "nickname"),            @Result(property = "user", column = "user_id",                    one = @One(select =                                "com.li.mapper.UserMapperAnnotation.getUserById"))    })    public List getPetByUserId(Integer userId);        //通过pet的id获取pet信息    @Select(value = " SELECT * FROM `pet` where id =#{id}")    @ResultMap("PetResuleMap")//复用上面的PetResuleMap    public Pet getPetById(Integer id);}

3.3练习

自己设计dept(部门)和emp(雇员)表,它们是一对多的关系。

  1. 通过查询dept,可以级联查询到所有的emp信息
  2. 通过查询emp,也可以级联查询到对应的dept信息
  3. 拓展思考:多对多关系