resultMap的高级结果映射和动态sql


目录

高级结果映射

一、表与表之间的关系

二、一对一

步骤

1.创建实体类

2.创建扩展类 

 3.将查询结果映射到扩展类中(映射文件中的resultMap设置映射关系)

三、一对多

1.创建实体类 (get set省略了)

2.编写sql语句 

3.创建扩展类 (get set方法省略)

4.映射Dto 

总结---多表关联查询的结果映射步骤

动态sql

一、选择结构

  1.1 if单条件选择

  1.2 choose 多条件选择 

二、循环结构 

三、扩展功能

3.1 where

3.2 set 

3.3 trim 

3.4 sql 

3.5 include



高级结果映射

  主要解决多表关联,要求输出两个表信息的问题,或者是多个表的信息的问题


一、表与表之间的关系

一对一

一对多

多对多(本质上还是一对多)

二、一对一

  首先创建两个表

淘宝中的个人账户
用户表  (登录名 密码 姓名  注册时间 状态 登录时间)
create table b_user(
 id  int not null primary key auto_increment,
 login_name  varchar(20),
 paw  varchar(20),
 create_date  varchar(20),
 status int ,
 last_login_date varchar(20)
)



用户详情表(身份证号 生日 联系电话 邮箱)
create table  b_user_info (
 id int not null primary key auto_increment,
 user_id int ,
 card_no varchar(18),
 birthday varchar(20),
 mobile varchar(20),
 email varchar(20)
)

要求:查询用户列表、显示用户的登录信息以及用户的详细信息

分析:

1.两个表之间的关系是一对一的 ---即一个用户有一个用户的详细信息

2. 然后分析谁应该是主表谁是从表,因为用户的详细信息可能没有填写,因此我们可以得知  主表:b_user  从表:b_user_info

3.分析使用说明连接两个表

    inner join  b_user中没有完善信息的用户可能无法显示

    left join b_user的信息全部显示,从表能关联上的也显示,关联不上的也显示以null填充

    right join 跟left join 是相同的  但是我们一般都是比较先与left join

因此分析得出使用 left join

select * from b_user  a left join b_user_info b on a.id=b.user_id

这样查询出来的结果为  

 我们发现查询出来有两个 id ---》 因此我们要进行别名设置来进行区分

select a.*,b.id detail_id,user_id,card_no,birthday,mobile,email from b_user a left join b_user_info b on a.id = b.user_id 

步骤

1.创建实体类

BUser 和BUserInfo

但是我们是要查询两个都包含的

一般情况我们会考虑 创建第三个实体类将两个表的属性全部写进去(这样是可以实现的但是比较low 即然后两个表进行改动后这个表也要进行改动,耦合性太高---等于工资低)

因此我们使用创建第三个实体类(扩展类)【一般是创建在dto结尾的包中】,这个类描述了2个实体之间的关系 

2.创建扩展类 

扩展类继承主表  创建属性为从表属性

class BUserDto extends BUser{

   //因为是一对一的直接创建一个成员变量为用户详细信息类

  private BUserInfo info ;

}

 3.将查询结果映射到扩展类中(映射文件中的resultMap设置映射关系)

<resultMap  type="com.sofwin.dto.BUserDto" id="map2">

  <id column="id"  property="id"/>

<result column="login_name" property="loginName"/>

<result column="pwd" property="pwd"/>
<result column="status" property="status"/>
<result column="create_date" property="createDate"/>
<result column="last_login_date" property="lastLoginDate"/>

  <!-- 自定义类型的属性映射

      association :进行1对1结果映射

      property:扩展类中自定义类型的属性的属性名

      javaType:当前属性的类型(设置全限定类名或者别名)

-->

<association property="info" javaType="buserinfo">

    <!--实体类的映射规则

     用于映射主键 id主键列可以不用映射,但是映射可以提高查询结果的封装效率,因此我们一般进行映射

property对应的是buserinfo类中的属性 
而column对应的是查询结果集的列名
-->

<id column="detail_id" property="id"/>
<result column="user_id" property="userId"/>
<result column="card_no" property="cardNo"/>
<result column="birthday" property="birthday"/>
<result column="mobile" property="mobile"/>
<result column="email" property="email"/>

</association>

</reusltMap>

<select id="selectUserInfo" resultMap="map2">
select a.*,b.id detail_id,user_id,card_no,birthday,mobile,email from b_user a left join b_user_info b on a.id = b.user_id
</select>

注意注意:

 

三、一对多

 问题:显示订单信息,并关联显示订单详情

创建两个表

b_oredermain   订单主表

b_orderdetail   订单详情表b_ordermain  订单主表

CREATE TABLE b_ordermain(
id INT NOT NULL PRIMARY KEY
AUTO_INCREMENT,
order_no VARCHAR(20) NOT NULL,
user_id INT,
status INT,
total INT
)

b_orderdetal 订单明细表
CREATE TABLE b_orderdetail(
id INT NOT NULL PRIMARY KEY
AUTO_INCREMENT,
main_id INT,
goods_id INT,
price INT,
num INT,
total INT
)

分析:

1.两个表之间的关系是一对多的 ---即一个订单主表有多个订单的详情表

2. 然后分析谁应该是主表谁是从表,因为是一个订单主表对应多个订单详情表,因此我们可以得知  主表:b_oredermain   从表:b_orderdetail 

1.创建实体类 (get set省略了)

b_oredermain   订单主表


public class BOrdermain {
   private Integer id;
   private String orderNo;
   private Integer userId;
   private Integer status;
   private Integer total;

}



b_orderdetail  订单详情表

public class BOrderDetal {
  private Integer id;
  private Integer mainId;
  private Integer goodsId;
  private Integer price;
  private Integer num;
  private Integer total;

}

2.编写sql语句 

sql语句还是要注意相同的列名要进行别名 进行区分

select a.* ,b.id detail_id,goods_id,price,num,b.total xj from b_ordermain a left join b_orderdetail b on a.id = b.main_id;

3.创建扩展类 (get set方法省略)

public class OrderMainDto extends OrderMain{
private List<OrderDetail> details;
}

这里是一对多 所以我们的属性是集合中存放多个订单详情表

4.映射Dto 

<resultMap id="map3" type="com.sofwin.dto.OrderMainDto">
<id column="id" property="id"/>
<result column="order_no" property="orderNo"/>
<result column="user_id" property="userId"/>
<result column="status" property="status"/>
<result column="total" property="total"/>

<!--对应一对多的结果映射采用 collection

   集合类型的属性的映射都采用的是collection 

  property :集合类型的属性的属性名

 ofType :当属性的泛型  全限定类名或者别名

-->

<collection property="details" ofType="orderdetail">

   <!-- 每个orderdeail的映射规则 -->
<id column="detail_id"
property="id"/>
<result column="goods_id" property="goodsId"/>
<result column="price" property="price"/>
<result column="num" property="num"/>
<result column="xj" property="total"/>
</collection>
</resultMap>
<select id="selectOrders" resultMap="map3">
select a.*,b.id detail_id,goods_id,price,num,b.total xj from b_ordermain a left join b_orderdetail b on a.id = b.main_id;
</select>

总结---多表关联查询的结果映射步骤

   1.首先使用java类来描述表间关系(Deo类中描述连个表之间的关系)

   2.将查询结果映射到扩展类(映射文件中的resultMap设置映射关系)

具体步骤

 1. 创建表

  2.创建实体类   

  3.分析主表从表  以及是一对一 还是一对多

  4.定义sql

  5.创建扩展类

  6.Dto映射


动态sql

 1.主要是解决我们根据条件不同,sql语句会发送动态变化,而我们无法在xml的映射文件中进行条件判断或者是循环判断等等 。

2.并且动态sql还能让我实现事务的一致性  ----如果以前我们都是在java中进行循环来查找,如果第二个发生错误,第一个已经执行,并没有回滚,这就违背了我们事务的特性。

基于以上的情况我们引入了动态sql来解决这些问题


一、选择结构

  1.1 if单条件选择

语法

jstl语句:<c:if test="基于el表达式的逻辑表达式">sdfsdf</c:if>
mybatis: <if test=""  >
            要加入的sql语句
          </if>

传入参数的三种情况  简单类型、自定义pojo、map类型 

自定义pojo类型

test 逻辑表达式:

   如果输入参数是自定义pojo类型,可以直接通过属性名进行判断

      如果逻辑表达式为真 if标签中的sql语句就会和上面的sql语句进行拼接
 

<select id="selectUsers" parameterType="user" resultMap="map1" timeout="1000">
      select id ids,name names,sex sexs from s_user
      where 1=1  (这个我们先这样 破坏了索引 --后面有解决方法)

<if test="name!=null and name!=' ' " > 

    and  name like '%#{name}%'

</if>

<if test="sex!=null " > 

    and  sex like '%#{sex}%'

</if>

简单类型 

 

<select id="selectUsers" parameterType="string"  resultMap="map1" timeout="1000">
      select id ids,name names,sex sexs from s_user  

<!--如果输入的简单数据类型 ,_parameter 为当前输入参数的值-->

<if test="_parameter" >

   where name like ' %#{value}%'

</if>

map类型 

List<User> selectUsers(@Param("name") String name,@Param("sex") Integer sex);                   这两个是相同的 ---是等同于的    
List<User> selectUsers(Map map); 

<select id="selectUsers"  resultMap="map1" timeout="1000">
      select id ids,name names,sex sexs from s_user where 1=1

<!-- 如果输入参数为map或者注解@Param类型,key当前输入参数的值 -->

<if test="sex!=null">

    and sex =#{sex}

</if>

 1.2 choose 多条件选择 

语法

jstl

  <c:choose>

    <c:when  test=" ">  </c:when>

   <c:when  test=" ">  </c:when>

   .... 

   <c:otherwise> </c:otherwise>

</c:choose>

mybatis

  <choose>

    <when  test=" ">  </when>

   <when  test=" ">  </when>

   .... 

   <otherwise> </otherwise>

</choose>

<select id="selectUsers"  resultMap="map1" timeout="1000">
      select id ids,name names,sex sexs from s_user where 1=1
      <choose>
          <when test="name!=null and name!=''">
              and name like '%${name}%'
          </when>
          <when test="sex!=null">
              and sex=#{sex}
          </when>
          <otherwise>
              and 2=2
          </otherwise>
      </choose>
  </select>

二、循环结构 

主要解决给定一个数组 按照数组汇总提供的id进行批量删除

{1,2,3,4}

语法 

jstl

 <c:foreach items="需要遍历的集合" var="当前对象" varStatus="获取索引">

  循环体 

</c:foreach>

mybatis

<foreach  collection="需要遍历的集合" item="当前对象"  index="当前索引" open="以什什么开头"  close="循环以什么结尾" seperator="循环以什么分割">

</foreach>
 

<!--如果输入参数是集合 collection为list

     如果输入参数是数组 collection为array

    如果输入参数是ppjo或者map collection为属性名或者key

-->

数组 

 <delete id="removeUsers" parameterType="int">
  	delete from s_user where id in
  
  	<foreach collection="array" item="id" open="(" close=")" separator=",">
  	   #{id}
  	</foreach>
  </delete>

集合 

<delete id="removeUsers" parameterType="int">
  	delete from s_user where id in
  	
  	<foreach collection="list" item="id" open="(" close=")" separator=",">
  	#{id}
  	</foreach>
  </delete>

POJO或者map 

 <delete id="removeUsers" parameterType="map">
  	delete from s_user where id in
  	  <!-- ids是map或者是popp中的数组或者集合的属性-->
  	<foreach collection="ids" item="id" open="(" close=")" separator=",">
  	   #{id}
  	</foreach>
  </delete>

 三、扩展功能

  3.1 where

自动增加where关键字,并去除第一个and,一般where标签内部需要使用选择结构

select id="selectUsers"  resultMap="map1" timeout="1000">
  	select id ids,name names,sex sexs from s_user
  	<where>
  		<if test="name!=null and name!=''">
  			and name like '%${name}%'
  		</if>
  		<if test="sex!=null">
  			and sex=#{sex}
  		</if>
  	</where>
  </select>

3.2 set 

自动增加set关键字,并取出最后一个 ,只能用在update语句

<update id="updateUser" parameterType="user" >
  
  	update s_user
  	<set>
  		<if test="name!=null and name!=''">
  			name=#{name},
  		</if>
  		<if test="sex">
  			sex=#{sex},
  		</if>
  	</set>
  	where id=#{id}
  </update>

3.3 trim 

可以构建where和set

<!--

prefix:增加前缀

suffix:增加后缀

prefixOverrides:覆盖第一指定字符

suffixOverrides:覆盖最后一个字符
-->
<trim prefix="" suffix="" prefixOverrides="" suffixOverrides=""></trim>

<update id="updateUser" parameterType="user" >
  
  	update s_user
    
    set的替换
  	<trim prefix="SeT" suffixOverrides=",">
  		<if test="name!=null and name!=''">
  			name=#{name},
  		</if>
  		<if test="sex">
  			sex=#{sex},
  		</if>
  		</trim>
  	where id=#{id}
  </update>

where的替换
<select id="selectUsers"  resultMap="map1" timeout="1000">
  	select 
    <include refid="tableColumns"></include>
    from s_user
  	<trim prefix="where" prefixOverrides="and">
  		<if test="name!=null and name!=''">
  			and name like '%${name}%'
  		</if>
  		<if test="sex!=null">
  			and sex=#{sex}
  		</if>
  	</trim>
  </select>

3.4 sql 

定义sql片段,解耦合,即xml中存在模板配置  可以做出sql片段

<sql id="tableColumns">
  id ids,name names,sex sexs
  </sql>

3.5 include

 引用某个sql片段

<select id="selectUsers"  resultMap="map1" timeout="1000">
  	select 
    <include refid="tableColumns"></include>
    from s_user
  	<where>
  		<if test="name!=null and name!=''">
  			and name like '%${name}%'
  		</if>
  		<if test="sex!=null">
  			and sex=#{sex}
  		</if>
  	</where>
  </select>

                
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值