zoukankan      html  css  js  c++  java
  • SpringBoot使用Mybatis注解进行一对多和多对多查询(2)

    SpringBoot使用Mybatis注解进行一对多和多对多查询

    GitHub的完整示例项目地址kingboy-springboot-data

    一、模拟的业务查询

    系统中的用户user都有唯一对应的地址信息address,每个用户可以有多量车car,类似如下结构

    |-- user
        |-- address
        |-- carList
            |-- car1
            |-- car2
    

      

    二、对应的实体类如下

    /省略setter/getter
    
    public class Address {
        private Long id;
        private String province;
        private String city;
    }
    
    public class Car {
        private Long id;
        private String color;
        private String name;
        //用户id
        private Long userId;
    }
    
    public class User {
        private Long id;
        //地址信息,和用户是一对一的关系
        private Address address;
        //地址id
        private Long addressId;
        //用户拥有的车,和用户是一对多的关系
        private List<Car> cars;
    }

    三、对应的建表语句和模拟数据如下

    CREATE TABLE IF NOT EXISTS `user` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `nick_name` varchar(50) DEFAULT NULL,
      `address_id` int(11) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    CREATE TABLE IF NOT EXISTS `address` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `province` varchar(50) DEFAULT NULL,
      `city` varchar(50) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    CREATE TABLE IF NOT EXISTS `car` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `color` varchar(50) DEFAULT NULL,
      `name` varchar(50) DEFAULT NULL,
      `user_id` int(11) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    INSERT INTO
        `user`
    VALUES
        ('1', 'baby', '1'),
        ('2', 'kingboy', '2'),
        ('3', 'boy', '3'),
        ('4', 'kingbaby', '4');
    
    INSERT INTO
        `address`
    VALUES
        ('1', '北京', '北京'),
        ('2', '天津', '天津'),
        ('3', '安徽', '宿州'),
        ('4', '广东', '广州');
    
    INSERT INTO
        `car`
    VALUES
        ('1', 'green', '路虎', '1'),
        ('2', 'white', '奔驰', '2'),
        ('3', 'blue', '玛莎拉蒂', '4'),
        ('4', 'yellow', '兰博基尼', '4');

    四、@One一对一映射

    以获取用户的唯一地址为例,首先我们定义一个根据地址id查询地址的查询方法

    public interface AddressRepository {
        /**
         * 根据地址id查询地址
         */
        @Select("SELECT * FROM `address` WHERE id = #{id}")
        Address findAddressById(Long id);
    }

    然后我们定义一个根据用户id查询用户的方法

    public interface UserRepository {
        @Select("SELECT * FROM `user` where id = #{id}")
        User findUserWithAddress(Long id);
    }

    这个时候我们查询出来的user对象中的address属性是空的,和address并没有任何关联。 
    那么我们要把user中的addressId传递给AddressRepository的查询地址的方法, 
    然后把查询出的地址对象address赋值给user的address属性,那么我们怎么做呢?

    public interface UserRepository {
        @Select("SELECT * FROM `user` where id = #{id}")
        @Results({
                @Result(property = "address", column = "address_id",
                        one = @One(select = "com.kingboy.repository.address.AddressRepository.findAddressById"))
        })
        User findUserWithAddress(Long id);
    }

    我们要使用@Resutl注解对返回的结果进行配置, 
    - property = “address”, 表示要将返回的查询结果赋值给user的address属性 
    - column = “address_id” 是指将user表中的address_id作为com.kingboy.repository.address.AddressRepository.findAddressById的查询参数 
    - one 表示这是一个一对一的查询 
    - @One(select = “方法全路径) 表示我们调用的方法

    五、@Many一对多查询

    以获取用户拥有的所有车car为例,首先我们定义一个根据用户id查询车的查询方法

    public interface CarRepository {
        /**
         * 根据用户id查询所有的车
         */
        @Select("SELECT * FROM `car` WHERE user_id = #{userId}")
        List<Car> findCarByUserId(Long userId);
    }
    

      然后我们定义一个根据用户id查询用户的方法

    public interface UserRepository {
        @Select("SELECT * FROM `user` where id = #{id}")
        User findUserWithAddress(Long id);
    }

    这个时候我们查询出来的user对象中的List属性是空的,和car的查询方法并没有任何关联。 
    那么我们要把user中的用户id传递给CarRepository的查询车的方法, 
    然后把查询出的集合对象List赋值给user的cars属性,那么我们怎么做呢?

    public interface UserRepository {
        /**
         * 查询带有车信息的用户===============演示一对多(关于多对多其实就是两个一对多组成)
         */
        @Select("SELECT * FROM `user` WHERE id = #{id}")
        @Results({
                @Result(property = "cars", column = "id",
                        many = @Many(select = "com.kingboy.repository.car.CarRepository.findCarByUserId"))
        })
        User getUserWithCar(Long id);
    }
    我们要使用@Resutl注解对返回的结果进行配置, 
    - property = “cars”, 表示要将返回的查询结果赋值给user的cars属性 
    - column = “id” 是指将user表中的用户主键id作为com.kingboy.repository.address.CarRepository.findCarByUserId的查询参数 
    - many 表示这是一个一对多的查询 
    - @Many(select = “方法全路径) 表示我们调用的方法, 方法参数userId就是上面column指定的列值

    六、@One @Many的总结

    首先我们统一下概念:查询Address或Car的方法,接下来统称为User的附属查询。

    共同点: 
    - 无论是一对一还是一对多,都是通过附属查询来实现的,我们需要定义这个附属查询方法。 
    - 在主查询方法中通过@One、@Many指定附属查询方法的全路径。 
    - 都通过column来传递参数给附属方法。

    不同点: 
    - 一对一,那么附属方法返回的是一个单独的对象 
    - 一对多,那么附属方法返回的是一个对象集合

  • 相关阅读:
    面试小结
    Everything工具使用
    记 · 工作一周年
    贝叶斯算法原理分析
    MySQL与Oracle主键Query性能测试结果
    K-meams文本聚类算法C++实现
    OPTICS光学算法
    页面添加内容后弹出框与跳转页面
    Webgrid参数格式
    页面2级分类
  • 原文地址:https://www.cnblogs.com/a8457013/p/9074930.html
Copyright © 2011-2022 走看看