其他解决方案的问题
在上一篇文档中,我们讨论了动态查询。本目录中,我们将探讨动态表链接的问题
目前其他操作SQL的技术方案,无论ORM还是非ORM,都有存在一个空白领域:只考虑到了动态where
,没有考虑动态join
。
动态JOIN
定义:如果某些动态查询条件针对其他表而非当前表。这意味着
-
条件满足时:先通过关联属性join到其他表,再对join得到的表添加动态where条件
-
条件不满足时:不能通 过关联属性join其他表
场景-1
让我们先来看第一个场景,这里用面向原生SQL的MyBatis为例
-
定义MyBatis Mapper接口
@Mapper
public interface BookMapper {
List<Book> findBooks(
@Nullable String name,
@Nullable String storeName,
@Nullable String storeWebsite
);
}这里 ,所有查询参数都可能为null,很明显,这是一个动态查询。
后面两个查询参数:
storeName
和storeWebsite
,其过滤条件并不施加在当前表BOOK
上,而是施加在父表BOOK_STORE上
。 即,当这两个参数中的任何一个非null时,都会生成对BOOK_STORE
表的JOIN,这种由参数值动态决定是否添加的表连接,在本文中被称为动态JOIN
。 -
定义MyBatis的SQL映射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="somepackage.BookMapper">
<select id="findBooks" resultType="somepackage.Book">
select * from BOOK as book
<if test="storeName != null or storeWebsite != null"> ❶
inner join BOOK_STORE as store
on book.STORE_ID = store.ID
</if>
<where>
<if test="name != null">
and book.NAME = #{name}
</if>
<if test="storeName != null"> ❷
and store.NAME = #{storeName}
</if>
<if test="storeWebsite != null">
and store.WEBSITE = #{storeWebsite} ❸
</if>
</where>
</select>
</mapper>其中,❶就是动态JOIN。然而对开发人员而言,❷和❸才是目的,❶是为支持❷和❸而不得不做的工作,其判断条件是一种负担。
也许你已经注意到了,❶的判断条件使用了
or
,这也不难理解。然而,这仅仅是最简单的两表之间动态连接,对于更深的多表连接操作而言,动态连接的复杂度会急剧上升!
场景-2
让我们再来看第二个场景,有了前面的例子作为基础,这个例子就不同任何业务耦合了。
<?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="somepackage.AMapper">
<select id="findAObjects" resultType="somepackage.A">
select distinct A.id
from A
<if test="bId != null or cId != null or dId != null or eId != null">
inner join B on A.ID = B.A_ID
</if>
<if test="cId != null or dId != null or eId != null">
inner join C on B.ID = C.B_ID
</if>
<if test="dId != null or eId != null">
inner join D on C.ID = D.C_ID
</if>
<if test="eId != null">
inner join E on D.ID = E.D_ID
</if>
<where>
<if test="aId != null">
and A.ID = #{aId}
</if>
<if test="bId != null">
and B.ID = #{bId}
</if>
<if test="cId != null">
and C.ID = #{cId}
</if>
<if test="dId != null">
and D.ID = #{dId}
</if>
<if test="eId != null">
and E.ID = #{eId}
</if>
</where>
</select>
</mapper>
这个例子逻辑很简单,A、B、C、D和E这五张表形成了一个JOIN链,每张表都一个动态查询条件。然而,正如你所见,动态JOIN的复杂度已经变得不可接受了。