本文博客地址:http://blog.csdn.net/soonfly/article/details/63688582 (转载请注明出处)
接着上文《关联关系association:1对1关联的三种方法 》的例子
一对多关系
[order表]–>[order_detail表]是1对多(1.n)关系。1个订单可以由多个订单分录(购买的商品)组成的。1对多关联关系可以理解为一个对象的内部有一个列表。
在后台系统中我们点击订单列表会进到订单详情页
有两种方式可以实现:
一、(推荐)用sql联合查询,使用collection标签
sql查询语句是这样的:
SELECT
`order`.*,`user`.username,`user`.address,`user`.cellphone,
`order_detail`.productname,`order_detail`.price,`order_detail`.num
FROM `order`
,`user`,`order_detail`
WHERE `order`.create_userid=`user`.id AND
`order_detail`.`order_id`=`order`.id AND
`order`.orderno='M201209012578917'
step1.我们已经有一个与表对应的Order类,但是没有分录列表字段。所以在Order类里新增List<OrderDetail> orderdetailList
属性:
public class Order {
Integer id;
String orderno;
Integer create_time;
Integer create_userid;
User user;
/* 添加分录列表 */
List<OrderDetail> orderdetailList;
/*下面get和set方法*/
getter and setter....
}
step2.创建接口及Xml
在twm.mybatisdemo.mapper包下的OrderMapper.xml和OrderMapper.java的基础上改进。
OrderMapper.java里添加方法:
//查询单个订单详情,关联查询用户信息以及订单明细
public List<Order> getDetailByOrderno() throws Exception;
OrderMapper.xml里添加一个resultMap和一个select:
<resultMap type="Order" id="Contain_DetailList_OrderMap" extends="OrderMap">
<!-- order中订单信息字段及关联的用户字段,和上面的OrderMap映射一样,这里只是扩充订单明细,extends继承上面的即可 -->
<!-- 配置关联订单明细信息 -->
<collection property="orderdetailList" ofType="OrderDetail">
<id column="id" property="id" />
<result column="productname" property="productname" />
<result column="num" property="num" />
<result column="price" property="price" />
</collection>
</resultMap>
<select id="getDetailByOrderno" parameterType="String" resultMap="Contain_DetailList_OrderMap">
SELECT
`order`.*,`user`.username,`user`.address,`user`.cellphone,
`order_detail`.productname,`order_detail`.price,`order_detail`.num
FROM `order`
,`user`,`order_detail`
WHERE `order`.create_userid=`user`.id AND
`order_detail`.`order_id`=`order`.id AND
`order`.orderno=#{orderno}
</select>
step3.调用
public static void main(String[] args) throws Exception {
SqlSession session = SqlSessionAssist.getSession();
OrderMapper ordermapper = session.getMapper(OrderMapper.class);
Order order = ordermapper.getDetailByOrderno("M201209012578917");
System.out.println(order.getOrderno() + ","
+ order.getUser().getUsername() + ","
+ order.getUser().getAddress() + ","
+ order.getUser().getCellphone());
List<OrderDetail> detailList=order.getOrderdetailList();
for (OrderDetail orderDetail : detailList) {
System.out.println(orderDetail.getProductname() + ","
+ orderDetail.getNum() + ","
+ orderDetail.getPrice());
}
}
结果:
M201209012578917,高天仪,北冥山庄,18911110000 iphone 8 plus,3,5700.0
擦~怎么只有一条明细呢?
看mybatis的日志
DEBUG [main] - ==> Preparing: SELECT
order
.*,user
.username,user
.address,user
.cellphone,
order_detail
.productname,order_detail
.price,order_detail
.num
FROMorder
,user
,order_detail
WHERE
order
.create_userid=user
.id AND
order_detail
.order_id
=order
.id ANDorder
.orderno=? DEBUG
[main] - ==> Parameters: M201209012578917(String) DEBUG [main] - <==
Total: 2
SQL查询出来确实是2条啊。
上网搜了一下,发现问题出在<id column="id" property="id" />
如果两表联查,主表和明细表的主键都是id的话,明细表的多条只能查询出来第一条。
解决办法:在SQL中加上order_detail.id as detail_id
,定义一个别名<id column="detail_id" property="id" />
再把<id column="id" property="id" />
改为<id column="detail_id" property="id" />
千万不要试图删了Contain_DetailList_OrderMap里的<id column="id" property="id" />
这句。这样没有主键,系统不会distinct去重记录的。
二、(不推荐)不使用sql联合查询,通过collection的延迟加载来实现
在上面的基础上修改:
step1.添加select片段,根据订单id,查询所有订单明细记录
<select id="SelectOrderDetail" parameterType="int" resultType="OrderDetail">
select * from `order_detail` where order_id=#{id}
</select>
step2.修改collection
collection的几个属性:
property:指定内部对象属性名
javaType:内部映射的对象的类型。
column:要传给select语句的参数,相当于指定外键字段。
select:指定用户查询语句的ID
<resultMap type="Order" id="Contain_DetailList_OrderMap" extends="OrderMap">
<!-- order中订单信息字段及关联的用户字段,和上面的OrderMap映射一样,这里只是扩充订单明细,extends继承上面的即可 -->
<!-- 配置关联订单明细信息 -->
<collection property="orderdetailList" select="SelectOrderDetail" column="id" />
</resultMap>
step3.修改getDetailByOrderno的select片段,删除联查order_detail相关的部分
<select id="getDetailByOrderno" parameterType="String" resultMap="Contain_DetailList_OrderMap">
SELECT `order`.*,`user`.username,`user`.address,`user`.cellphone
FROM `order` ,`user`
WHERE `order`.create_userid=`user`.id and
`order`.orderno=#{orderno}
</select>
运行结果:
DEBUG [main] - ==> Preparing: SELECT
order
.*,user
.username,user
.address,user
.cellphone FROMorder
,user
WHEREorder
.create_userid=user
.id andorder
.orderno=?
DEBUG [main] - ==> Parameters: M201209012578917(String) DEBUG [main] -
====> Preparing: select * fromorder_detail
where order_id=? DEBUG [main] - ====> Parameters: 1(Integer) DEBUG [main] - <==== Total:
2 DEBUG [main] - <== Total: 1
M201209012578917,高天仪,北冥山庄,18911110000 iphone 8 plus,3,5700.0
华为G7,2,2700.0
可以看到存在N+1问题,只不过这种场景下N永远是1。
原来用一个联合查询可以解决的,现在需要用两次查询。
本文博客地址:http://blog.csdn.net/soonfly/article/details/63688582 (转载请注明出处)