I. Introduction
Through dynamic SQL, we can compile complex SQL, but the previous examples are single-table queries. In actual development, of course, not all single-table queries. Many times we need to carry out related multi-table queries (some companies still try to use single-table queries for performance). The relationship between tables and tables can be divided into one-to-one, one-to-many, and many-to-many. How to write it?
Create tables and entities first:
CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(32) NOT NULL COMMENT 'User name', `birthday` date DEFAULT NULL COMMENT 'Birthday', `sex` char(1) DEFAULT NULL COMMENT 'Gender', `address` varchar(256) DEFAULT NULL COMMENT 'address', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of user -- ---------------------------- INSERT INTO `user` VALUES ('1', 'Wang Wu', null, '2', null); INSERT INTO `user` VALUES ('10', 'Zhang San', '2014-07-10', '1', 'Beijing City'); INSERT INTO `user` VALUES ('16', 'Zhang Xiaoming', null, '1', 'Zhengzhou, Henan'); INSERT INTO `user` VALUES ('22', 'Chen Xiaoming', null, '1', 'Zhengzhou, Henan'); INSERT INTO `user` VALUES ('24', 'Zhang Sanfeng', null, '1', 'Zhengzhou, Henan'); INSERT INTO `user` VALUES ('25', 'Chen Xiaoming', null, '1', 'Zhengzhou, Henan'); INSERT INTO `user` VALUES ('26', 'Wang Wu', null, null, null); DROP TABLE IF EXISTS `order`; CREATE TABLE `order` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL COMMENT 'Order user id', `number` varchar(32) NOT NULL COMMENT 'Order number', `createtime` datetime NOT NULL COMMENT 'Order creation time', `note` varchar(100) DEFAULT NULL COMMENT 'Remarks', PRIMARY KEY (`id`), KEY `FK_order_1` (`user_id`), CONSTRAINT `FK_order_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of order -- ---------------------------- INSERT INTO `order` VALUES ('3', '1', '1000010', '2015-02-04 13:22:35', null); INSERT INTO `order` VALUES ('4', '1', '1000011', '2015-02-03 13:22:41', null); INSERT INTO `order` VALUES ('5', '10', '1000012', '2015-02-12 16:13:23', null);
User:
@Data public class User implements Serializable { private Integer id; // User name private String username; // Gender private String sex; // Birthday private Date birthday; // address private String address; }
Order:
@Data public class Order { // Order id private int id; // user id private Integer userId; // Order number private String number; // Order creation time private Date createtime; // Remarks private String note; }
2. One-to-one
Order form and user table, an order is created by a customer, when we check the user through the order, it is a one-to-one relationship.
There are two ways to achieve this.
2.1. Use resultType
You can modify the order pojo class, which includes order information and user information. When returning to the object, mybatis automatically injects user information into it and creates OrderUserVO:
@Data public class OrderUserVO extends Order { /** * Customer name */ private String username; /** * Customer address */ private String address; }
xml file:
<select id="queryOrderUser" resultType="com.yuanqinnan.pojo.OrderUserVO"> SELECTo.id,o.user_id,userId,o.number,o.createtime,o.note,u.username,u.address FROM `order` o LEFT JOIN `user` u ON o.user_id = u.id </select>
Interface:
public interface OrderMapper { List<Order> queryOrderAll(); List<Order> queryOrderAll2(); List<OrderUserVO> queryOrderUser(); }
Test:
@Test public void queryOrderUser(){ SqlSession sqlSession = this.sqlSessionFactory.openSession(); OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class); List<OrderUserVO> list = orderMapper.queryOrderUser(); for (OrderUserVO u : list) { System.out.println(u); } sqlSession.close(); }
Result:
A special pojo class is defined as the output type, in which all fields of the sql query result set are defined. This method is relatively simple and widely used in enterprises.
2.2. Use resultMap
Using resultMap, a special resultMap is defined to map one-to-one query results, modify the Order class, add the User attribute to the Order class, and use the user attribute to store the user information of the associated query. Because the order Association query user is a one-to-one relationship, a single User object is used to store the user information of the associated query.
@Data public class Order { // Order id private int id; // user id private Integer userId; // Order number private String number; // Order creation time private Date createtime; // Remarks private String note; /** * Customer */ private User user; }
First define resultMap:
<resultMap type="com.yuanqinnan.model.Order" id="orderUserResultMap"> <id property="id" column="id"/> <result property="userId" column="user_id"/> <result property="number" column="number"/> <result property="createtime" column="createtime"/> <result property="note" column="note"/> <!-- association : Configure one-to-one attributes --> <!-- property:order Inside User Attribute name --> <!-- javaType:Attribute types --> <association property="user" javaType="user"> <!-- id:Declare the primary key to indicate user_id Is the unique identifier of the associated query object--> <id property="id" column="user_id"/> <result property="username" column="username"/> <result property="address" column="address"/> </association> </resultMap>
Add queries again
<!-- One-to-one associations, queries orders, orders containing user attributes --> <select id="queryOrderUserResultMap" resultMap="orderUserResultMap"> SELECT o.id,o.user_id,o.number,o.createtime,o.note,u.username,u.address FROM `order` o LEFT JOIN `user` u ON o.user_id = u.id </select>
Interface:
List<Order> queryOrderUserResultMap();
Test:
@Test public void queryOrderUserResultMap(){ SqlSession sqlSession = this.sqlSessionFactory.openSession(); OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class); List<Order> list = orderMapper.queryOrderUserResultMap(); for (Order u : list) { System.out.println(u); } sqlSession.close(); }
Result:
3. One-to-many
A customer will create multiple orders, when we query customer orders, it will produce a one-to-many situation, let's take this as an example.
First, we add an order list to the User class
@Data public class User implements Serializable { //id private Integer id; //User name private String username; //Gender private String sex; //Birthday private Date birthday; //address private String address; //Order list private List<Order> orderList; }
Then add resultMap:
<resultMap type="com.yuanqinnan.model.Order" id="orderUserResultMap"> <id property="id" column="id"/> <result property="userId" column="user_id"/> <result property="number" column="number"/> <result property="createtime" column="createtime"/> <result property="note" column="note"/> <!-- association : Configure one-to-one attributes --> <!-- property:order Inside User Attribute name --> <!-- javaType:Attribute types --> <association property="user" javaType="user"> <!-- id:Declare the primary key to indicate user_id Is the unique identifier of the associated query object--> <id property="id" column="user_id"/> <result property="username" column="username"/> <result property="address" column="address"/> </association> </resultMap>
Add queries:
<!-- One-to-one associations, queries orders, orders containing user attributes --> <select id="queryOrderUserResultMap" resultMap="orderUserResultMap"> SELECT o.id,o.user_id,o.number,o.createtime,o.note,u.username,u.address FROM `order` o LEFT JOIN `user` u ON o.user_id = u.id </select>
Test:
@Test public void queryUserOrder(){ SqlSession sqlSession = this.sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> list = userMapper.queryUserOrder(); for (User u : list) { System.out.println(u); } sqlSession.close(); }
Result:
4. Many-to-many
Many-to-many relationships require intermediate tables to maintain. For example, an order contains multiple products, and a product can appear in multiple orders. At this time, we need an order product table as the intermediate table. So we need to add two new tables, the product table and the order product table.
CREATE TABLE `product` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) DEFAULT NULL COMMENT 'Product name', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf; -- ---------------------------- -- Records of product -- --------------------------- INSERT INTO product VALUES('1','Notebook computer'); INSERT INTO product VALUES('2','Mi phones'); CREATE TABLE `order_product` ( `id` int(11) NOT NULL AUTO_INCREMENT, `oid` int(11) DEFAULT NULL COMMENT 'Order id', `pid` int(11) DEFAULT NULL COMMENT 'product id', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 -- ---------------------------- -- Records of order_product -- --------------------------- INSERT INTO order_product VALUES('1','3','1'); INSERT INTO order_product VALUES('2','3','2'); INSERT INTO order_product VALUES('3','4','1');
The many-to-many queries we may encounter are: query all products of this order or query all orders of this product.
At this time, our orders and product lists should correspond to multiple intermediate tables, so entities should be designed as follows:
order entities add intermediate tables:
@Data public class Order { // Order id private int id; // user id private Integer userId; // Order number private String number; // Order creation time private Date createtime; // Remarks private String note; //Customer private User user; //Intermediate table private List<OrderProduct> products; }
OrderProduct:
@Data public class OrderProduct { private Integer id; //Order key private Integer oid; //Product primary key private Integer pid; //Order private Order order; //product private Product product; }
product:
@Data public class Product { //product id private Integer id; //Product name private String name; //Intermediate table List<OrderProduct> orders; }
resultmap:
<resultMap type="com.yuanqinnan.model.Order" id="orderBean"> <id column="id" property="id"/> <result property="userId" column="user_id"/> <result property="number" column="number"/> <result property="createtime" column="createtime"/> <result property="note" column="note"/> <collection property="products" ofType="com.yuanqinnan.model.OrderProduct"> <id column="oiid" property="id"/> <result column="oid" property="oid"/> <result column="pid" property="pid"/> <association property="product" javaType="com.yuanqinnan.model.Product"> <id column="pid" property="id"/> <result column="pname" property="name"/> </association> </collection> </resultMap>
New product information method for inquiring orders:
<select id="listOrder" resultMap="orderBean"> SELECT o.*, o.id oid, p.id pid, oi.id oiid, p.NAME pname FROM `order` o LEFT JOIN order_product oi ON o.id = oi.oid LEFT JOIN product p ON p.id = oi.pid </select>
Test:
@Test public void listOrder(){ SqlSession sqlSession = this.sqlSessionFactory.openSession(); OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class); List<Order> list = orderMapper.listOrder(); for (Order u : list) { System.out.println(u); } sqlSession.close(); }
Result: