宽为限 紧用功 工夫到 滞塞通
接着上一篇博文,我又回来了
业务场景
商城购物,用户可以有多个订单,每个订单可以有多个商品。它们间的关系是:
- 用户对订单,一对多,订单对用户,一对一;
- 订单对订单明细,一对多,订单明细对订单多对一;
- 订单明细对订单明细项,一对一,订单明细项对订单明细,一对一;
- 订单明细项对商品,一对一,商品对订单明细项,一对一;
- 订单明细项对订单,多对一;
- 用户对商品,多对多。
下图是从用户开始到商品间顺的关系
根据数据库开始编码
1、用户实体类
package mybatis.cascade.test.po;
/**
* @Description: 用户实体
* @author 浮华
* @date 2017年8月9日,下午9:07:33
*
*/
public class User {
/**
* fdId
*/
private String fdId;
public String getFdId() {
return fdId;
}
/**
* 用户名
*/
private String fdName;
public String getFdName() {
return fdName;
}
public void setFdName(String fdName) {
this.fdName = fdName;
}
/**
* 手机号
*/
private String fdPhone;
public String getFdPhone() {
return fdPhone;
}
public void setFdPhone(String fdPhone) {
this.fdPhone = fdPhone;
}
/**
* 地址
*/
private String fdAddress;
public String getFdAddress() {
return fdAddress;
}
public void setFdAddress(String fdAddress) {
this.fdAddress = fdAddress;
}
}
用户类本身无任何关联关系,是非常干净滴。它的Mapper和xml文件也很简单
UserMapper.java
package mybatis.cascade.test.mapper;
import mybatis.cascade.test.po.User;
public interface UserMapper {
/**
* 通过id获取用户
* @param fdId
* @return
*/
public User getUserById(String fdId);
}
userMapper.xml
<?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="mybatis.cascade.test.mapper.UserMapper">
<!-- 用户 -->
<resultMap type="user1" id="userMap">
<id property="fdId" column="fd_id" />
<result property="fdName" column="fd_name" />
<result property="fdPhone" column="fd_phone" />
<result property="fdAddress" column="fd_address" />
</resultMap>
<select id="getUserById" resultMap="userMap">
select * from g_user where fd_id = #{fdId}
</select>
</mapper>
2、订单实体类
package mybatis.cascade.test.po;
import java.util.Date;
import java.util.List;
/**
* @Description: 客户订单
* @author 浮华
* @date 2017年8月9日,下午9:13:31
*
*/
public class Orders {
/**
* fdId
*/
private String fdId;
public String getFdId() {
return fdId;
}
/**
* 订单名(号)
*/
private String fdName;
public String getFdName() {
return fdName;
}
public void setFdName(String fdName) {
this.fdName = fdName;
}
/**
* 订单明细
*/
private List<OrderItem> orderItemList;
public List<OrderItem> getOrderItemList() {
return orderItemList;
}
public void setOrderItemList(List<OrderItem> orderItemList) {
this.orderItemList = orderItemList;
}
/**
* 订单总价
*/
private double fdTotalPrices;
public double getFdTotalPrices() {
return fdTotalPrices;
}
public void setFdTotalPrices(double fdTotalPrices) {
this.fdTotalPrices = fdTotalPrices;
}
/**
* 下单用户(订单角度,一对一)
*/
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
/**
* 下单时间
*/
private Date fdOrderDateTime;
public Date getFdOrderDateTime() {
return fdOrderDateTime;
}
public void setFdOrderDateTime(Date fdOrderDateTime) {
this.fdOrderDateTime = fdOrderDateTime;
}
}
订单类就开始不单纯了,它关联了用户private User user;
及订单明细private List<OrderItem> orderItemList;
,与用户的关系是一对一,与订单明细的关系是一对多。
我们看看它的Mapper和xml
OrdersMapper.java
package mybatis.cascade.test.mapper;
import java.util.List;
import mybatis.cascade.test.po.Orders;
public interface OrdersMapper {
/**
* 通过id获取订单
* @param fdId
* @return
*/
public Orders getOrdersById(String fdId);
/**
* 通过用户id获取用户订单
* @param fdUserId
* @return
*/
public List<Orders> getOrdersListByUserId(String fdUserId);
}
一个标配的getOrdersById(String fdId)
方法,一个getOrdersListByUserId(String fdUserId)
方法,这个方法就是用户关联订单的那条线。一对多,通过用户id可以获取该用户的所有订单。
ordersMapper.xml
<?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="mybatis.cascade.test.mapper.OrdersMapper">
<!-- 订单 -->
<resultMap type="orders1" id="ordersMap">
<id property="fdId" column="fd_id" />
<result property="fdName" column="fd_name" />
<result property="fdTotalPrices" column="fd_total_prices" />
<result property="fdOrderDateTime" column="fd_order_datetime" />
<!-- 用户,一对一 -->
<association property="user" column="fd_user_id"
select="mybatis.cascade.test.mapper.UserMapper.getUserById" />
<!-- 订单明细项,一对多 -->
<collection property="orderItemList" column="fd_id"
select="mybatis.cascade.test.mapper.OrderItemMapper.getOrderItemListByOrderId" />
</resultMap>
<select id="getOrdersById" resultMap="ordersMap">
select * from g_orders where fd_id = #{fdId}
</select>
<select id="getOrdersListByUserId" resultMap="ordersMap">
select * from g_orders where fd_user_id = #{fdUserId}
</select>
</mapper>
看 resultMap,简单属性略讲。
①关联用户的配置:<association property="user" column="fd_user_id"
,
select="mybatis.cascade.test.mapper.UserMapper.getUserById" />
property=”user”,当前Order类的user属性;column=”fd_user_id”,Order类对应数据库表的关联用户的fd_id;select=”mybatis.cascade.test.mapper.UserMapper.getUserById”,拿到fd_user_id 在这里指定的地方去查询,这里的就是你mybatis.cascade.test.mapper.UserMapper.java文件中的getUserById(String fdId))
方法咯。
②关联明细项的配置:<collection property="orderItemList" column="fd_id"
,
select="mybatis.cascade.test.mapper.OrderItemMapper.getOrderItemListByOrderId" />
同上,这里column=”fd_id”要讲一下,因为一个订单可以有多个订单明细嘛,所以订单明细可以通过订单id来查,所以这里要的column就是订单自己的id咯。
3、订单明细实体类
package mybatis.cascade.test.po;
/**
* @Description: 订单明细
* @author 浮华
* @date 2017年8月10日,下午11:53:22
*
*/
public class OrderItem {
/**
* fdId
*/
private String fdId;
public String getFdId() {
return fdId;
}
/**
* 所属订单,一对一
*/
private Orders orders;
public Orders getOrders() {
return orders;
}
public void setOrders(Orders orders) {
this.orders = orders;
}
/**
* 商品记录项,一对一(不是直接关联商品而是关联一个商品记录项)
*/
private OrderDetail orderDetail;
public OrderDetail getOrderDetail() {
return orderDetail;
}
public void setOrderDetail(OrderDetail orderDetail) {
this.orderDetail = orderDetail;
}
}
嗯,订单明细,我们来看看。
一个private Orders orders;
,关联用户;一个private OrderDetail orderDetail;
关联。。。等等,OrderDetail 这个是啥? 不是订单明细直接就可以关联商品了吗?
一开始博主也是订单明细直接关联商品的,但后来发现问题了所以就加了这个OrderDetail订单明细项,具体啥问题呢,我们稍后再聊。
接下来看看Mapper和xml文件:
OrderItemMapper .java
package mybatis.cascade.test.mapper;
import java.util.List;
import mybatis.cascade.test.po.OrderItem;
public interface OrderItemMapper {
/**
* 通过id获取订单明细
* @param fdId
* @return
*/
public OrderItem getOrderItemById(String fdId);
/**
* 通过订单id 获取订单明细列表
* @param fdOrderId
* @return
*/
public List<OrderItem> getOrderItemListByOrderId(String fdOrderId);
}
通订单实体一样,一个标配,一个通过订单id获取属于该订单的所有订单明细。
orderItemMapper.xml
<?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="mybatis.cascade.test.mapper.OrderItemMapper">
<!-- 订单明细项 -->
<resultMap type="orderItem1" id="orderItemMap">
<id property="fdId" column="fd_id" />
<!-- 订单,一对一 -->
<association property="orders" column="fd_order_id"
select="mybatis.cascade.test.mapper.OrdersMapper.getOrdersById" />
<!-- 订单明细,一对一 -->
<association property="orderDetail" column="fd_order_detail_id"
select="mybatis.cascade.test.mapper.OrderDetailMapper.getOrderDetailById" />
</resultMap>
<select id="getOrderItemById" resultMap="orderItemMap">
select * from g_order_item where fd_id = #{fdId}
</select>
<!-- 通过订单id,获取订单明细项 -->
<select id="getOrderItemListByOrderId" resultMap="orderItemMap">
select * from g_order_item where fd_order_id = #{fdOrderId}
</select>
</mapper>
看看它的 resultMap,很简单,都是一对一关联关系,上面讲过了 yes略过。
4、订单明细项
package mybatis.cascade.test.po;
/**
* @Description: 订单明细商品项实体
* @author 浮华
* @date 2017年8月9日,下午9:23:56
*
*/
public class OrderDetail {
/**
* fdId
*/
private String fdId;
public String getFdId() {
return fdId;
}
/**
* 所属订单(订单角度,一对一)
*/
private Orders orders;
public Orders getOrders() {
return orders;
}
public void setOrders(Orders orders) {
this.orders = orders;
}
/**
* 所属商品(订单角度,一对一)
*/
private Commodity commodity;
public Commodity getCommodity() {
return commodity;
}
}
额,看了这个Mapper和xml都不想贴出来了,都一样的! 唉~ 一开始还真不知道要你何用 ╮(╯▽╰)╭,不能厚此薄彼 是吧,还是牵出来溜溜 (*^_^*)
OrderDetailMapper .java
package mybatis.cascade.test.mapper;
import mybatis.cascade.test.po.OrderDetail;
public interface OrderDetailMapper {
/**
* 通过id获取订单明细商品项
* @param fdId
* @return
*/
public OrderDetail getOrderDetailById(String fdId);
}
嗯,也有点不一样吧,这里没有获取明细项List的是吧,因为这里已经没必要了,它的作用和OrderItem的确很像,所以它哪里有了这里就不需要了。
orderDetailMapper.xml
<?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="mybatis.cascade.test.mapper.OrderDetailMapper">
<!-- 订单明细商品项 -->
<resultMap type="orderDetail1" id="orderDetailMap">
<id property="fdId" column="fd_id" />
<!-- 用户订单,一对一 -->
<association property="orders" column="fd_order_id"
select="mybatis.cascade.test.mapper.OrdersMapper.getOrdersById" />
<!-- 商品,一对一 -->
<association property="commodity" column="fd_commodity_id"
select="mybatis.cascade.test.mapper.CommodityMapper.getCommodityById" />
</resultMap>
<select id="getOrderDetailById" resultMap="orderDetailMap">
select * from g_order_detail where fd_id = #{fdId}
</select>
</mapper>
OK,明细项结束,那我们顺便把上面留下的疑问也结束掉吧!
为什么OrderDetail作用与OrderItem类似,不用OrderItem直接关联商品而要通过它呢? 看一下我之前没有明细项这个中间实体时产生的问题吧
数据库里的数据
这里订单d01有5个商品,正常来说可以查出5个商品的是吧
实际查出来的结果
测试代码里是 orderDetail.getCommodity(); 之前是这里直接关联的商品,那为什么实际查出来的只有4个呢? 是这样的,因为用户购买的相同的商品,而在订单表明细表里记录的商品id是一样的,所以查询商品时就算一个了,这相当于是查的商品种类。
5、商品实体类
package mybatis.cascade.test.po;
/**
* @Description: 商品实体
* @author 浮华
* @date 2017年8月10日,下午11:52:40
*
*/
public class Commodity {
/**
* fdId
*/
private String fdId;
public String getFdId() {
return fdId;
}
/**
* 商品名
*/
private String fdName;
public String getFdName() {
return fdName;
}
public void setFdName(String fdName) {
this.fdName = fdName;
}
/**
* 单价
*/
private double fdPrice;
public double getFdPrice() {
return fdPrice;
}
public void setFdPrice(double fdPrice) {
this.fdPrice = fdPrice;
}
/**
* 商品描述
*/
private String fdDescribe;
public String getFdDescribe() {
return fdDescribe;
}
public void setFdDescribe(String fdDescribe) {
this.fdDescribe = fdDescribe;
}
/**
* 库存
*/
private Integer fdReserve;
public Integer getFdReserve() {
return fdReserve;
}
public void setFdReserve(Integer fdReserve) {
this.fdReserve = fdReserve;
}
}
和用户实体类一样的单纯
CommodityMapper.java
package mybatis.cascade.test.mapper;
import mybatis.cascade.test.po.Commodity;
public interface CommodityMapper {
/**
* 通过id获取商品
* @param fdId
* @return
*/
public Commodity getCommodityById(String fdId);
}
commodityMapper.xml
<?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="mybatis.cascade.test.mapper.CommodityMapper">
<!-- 商品 -->
<resultMap type="commodity1" id="commodityMap">
<id property="fdId" column="fd_id" />
<result property="fdName" column="fd_name" />
<result property="fdPrice" column="fd_price" />
<result property="fdDescribe" column="fd_describe" />
<result property="fdReserve" column="fd_reserve" />
</resultMap>
<select id="getCommodityById" resultMap="commodityMap">
select * from g_commodity where fd_id = #{fdId}
</select>
</mapper>
最后我们来看看测试类
package mybatis.cascade.test.test;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import mybatis.cascade.test.mapper.OrdersMapper;
import mybatis.cascade.test.po.Commodity;
import mybatis.cascade.test.po.OrderDetail;
import mybatis.cascade.test.po.OrderItem;
import mybatis.cascade.test.po.Orders;
import mybatis.cascade.test.po.User;
import mybatis.cascade.test.util.SqlSessionFactoryUtil;
/**
* @Description: mybatis级联测试
* @author 浮华
* @date 2017年8月9日,下午9:40:33
*
*/
public class TestMain {
public static void main(String[] args) {
SqlSession sqlSession = null;
try {
sqlSession = SqlSessionFactoryUtil.openSqlSession();
// 创建订单代理对象
OrdersMapper ordersMapper = sqlSession.getMapper(OrdersMapper.class);
/**
* 通过用户id获取订单
*/
List<Orders> ordersListByUserId = ordersMapper.getOrdersListByUserId("u01");
for(Orders order : ordersListByUserId) {
System.out.println("\n" + order.getFdName());
// 订单关联的用户(一对一)
User user = order.getUser();
System.out.println("客户名称:" + user.getFdName());
// 获取订单商品项(一对多)
List<OrderItem> orderItemList = order.getOrderItemList();
for (OrderItem orderItem : orderItemList) {
// 之前把这过商品过渡类忽略了,然后相同id的商品就合一起了。
OrderDetail orderDetail = orderItem.getOrderDetail();
// 终于得到商品列表
Commodity commodity = orderDetail.getCommodity();
String fdName = commodity.getFdName();
System.out.println(fdName);
}
}
} finally {
if(sqlSession != null) {
sqlSession.close();
}
}
}
}
运行结果
d01订单这里也是4个,因为这里也4条数据
虽然说实际上不会这样找商品,找到了也没什么意义,多个商品可以直接在订单明细那里记录数量就行,但一开始想的就是订单里有几个商品我就要通过用户id找到他当前订单的几个商品,所以就酱紫搞咯 \(^o^)/YES!
奉上源码
https://github.com/zgmFlashy/mybatis_test/tree/master/mybatis_cascade