作为一个iOS开发,学一点后端的知识,更好的与后端在平时业务中对话,我觉得还是有必要的。
本篇文章,我就说明下如何做一对多的列表输出。
不管有没有学过后端,我相信大家基本都知道连表查询是可以使用join
的,我是用的mybatis做数据库操作,mybatis有个collection标签,可以用将关联表的数据聚合到主表中,比如我有个活动表activity,有个票种表ticket,活动表一对多票种表,我在查询活动表的时候需要将票种数据聚合到活动vo的tickets里。就这样,脑子里根深蒂固的思想,再加上网上搂了一圈,全都是如何使用mybatis collection标签或者子查询做一对多输出的,让我认为后端的列表一对多输出都是直接一遍从数据库查出来的,于是,我开始一点点的折腾。
使用<collection>
,我们需要解决几个问题:
- 为了防止activity与ticket有字段重合,我需要个ticket的字段每个都起别名,这部分还好,后面我发现,mybatis-generator生成的<sql>标签有这个数据,这个可以用idea的多行游标操作简化起别名的操作(我建议是直接在字段名后增加_表名_ali,防止起的别名太短了导致另外的重名)
- 然后还要讲每个别名映射到ticket的java对象属性去,这也算是个体力活
- 这个别名sql还需要具备带参数的功能,毕竟table的别名不能确定,幸好,
<sql>
标签可以传参数,这个问题也解决了 - 构建ActivityVO还需要activity的BaseResutlMap中所有的字段,幸好,resultMap可以允许继承
最终,研究了一整个下午,我才写完了这么个可以自定义的查询
ticket的sql
<sql id="ActivityTicketListAlias">
${tableName}.id id_ticket_ali,
${tableName}.activity_id activity_id_ticket_ali,
${tableName}.name name_ticket_ali,
${tableName}.count count_ticket_ali,
${tableName}.pay_type pay_type_ticket_ali,
${tableName}.price price_ticket_ali,
${tableName}.desc desc_ticket_ali,
${tableName}.sex sex_ticket_ali,
${tableName}.end_time end_time_ticket_ali,
${tableName}.member_level member_level_ticket_ali,
${tableName}.status status_ticket_ali,
${tableName}.create_time create_time_ticket_ali,
${tableName}.update_time update_time_ticket_ali
</sql>
ticket别名后映射的resutlMap
<resultMap id="ActivityTicketList" type="com.qinyi.renhai.entity.RhActivityTicket" >
<id column="id_ticket_ali" property="id" jdbcType="INTEGER" />
<result column="activity_id_ticket_ali" property="activityId"/>
<result column="name_ticket_ali" property="name"/>
<result column="count_ticket_ali" property="count"/>
<result column="pay_type_ticket_ali" property="payType"/>
<result column="price_ticket_ali" property="price"/>
<result column="desc_ticket_ali" property="desc"/>
<result column="sex_ticket_ali" property="sex"/>
<result column="end_time_ticket_ali" property="endTime"/>
<result column="member_level_ticket_ali" property="memberLevel"/>
<result column="status_ticket_ali" property="status"/>
<result column="create_time_ticket_ali" property="createTime"/>
<result column="update_time_ticket_ali" property="updateTime"/>
</resultMap>
ActivityVO查询的map(包含ticket的sql的使用)
<resultMap id="RhActivityVO" type="com.qinyi.renhai.entity.activity.RhActivityVO" extends="com.qinyi.renhai.mapper.RhActivityMapper.BaseResultMap">
<collection property="tickets" resultMap="ActivityTicketList" />
</resultMap>
<!--查询我的活动列表-->
<select id="getMyRegisteredActivities" resultMap="RhActivityVO">
SELECT a.*,
<include refid="ActivityTicketListAlias">
<property name="tableName" value="t"/>
</include>
FROM rh_activity a
JOIN rh_activity_ticket t ON a.activity_id = t.activity_id
JOIN rh_activity_registration r on r.activity_id = a.activity_id
WHERE r.member_id = #{userId}
order by a.end_time desc
</select>
写完这些,数据也是能够正常输出了,也能完美的定制掉每个表的映射别名等等,沾沾自喜的同时,我不经怀疑起,现在都2023年,后端仅仅为了一个一对多查询,就要写这么多的体力活吗
另寻他法
有没有更加简便的方法呢,我在网上查来查去,gpt也问了一圈,居然都没有人能给我更加简便的方法,然后,我向我们的后端请教了一下
短短3句对话,瞬间感觉到五雷轰顶,其实当我们后端说查两次聚合的时候,我瞬间有点不妙的感觉了,头顶好像有什么东西要出来似得(其实我之前也不是没有想过java的逻辑操作,只不过当时我并没有想到是去次表查关联数据,而是想的是for循环去次表查数据,当时觉得这种操作太low,就完全不考虑了)
PS
后面的操作估计大家都懂了,有点奇怪的是,网上居然从来没有人提起过(可能是我查询的关键词不对),不过,虽然路途很艰辛,我也更好的学习了mybatis的相关知识,对连表查询有了更深的理解(虽然接口用不了,但是cms什么的数据聚合输出总是需要连表的呀~)