目录
传送门:
一对多和多对一是出于角度的不同,若 用户:该用户创建的文章类型 是一对多。
那反过来 该用户创建的文章类型:用户便是多对一。
实体类:
/** * @author Alex * 用户实体类 */ @Data public class IUser { private String userName; private String email; private String passWord; private Date birth; private int gender; /** * user:type =1:n */ private List<IType> types; }
@Data public class IType { /** * 文章类型名称 */ private String name; /** * type:user = n:1 */ private IUser user; }
通过SQL角度解决
一对多:查询指定用户共创建了那些文章类型
在IUserMapper.java接口创建查询用户的方法、并在IUserMapper.xml中实现这个接口方法。
/** *查询指定用户及所创建的文章 */ IUser queryUser(int uId);
集合-collection(1:n)的使用:
处理方式一:查询条件嵌套
<resultMap id="userMap" type="com.example.demo.domain.entity.IUser">
<result column="user_name" property="userName"/>
<collection property="types" javaType="ArrayList" column="u_id" select="queryTypeByUid"/>
</resultMap>
<resultMap id="typeMap" type="com.example.demo.domain.entity.IType">
<result column="type_name" property="name"/>
</resultMap>
<select id="queryUser" resultMap="userMap">
select u_id,user_name from t_user where u_id =#{uId}
</select>
<select id="queryTypeByUid" resultMap="typeMap">
select type_name from t_type where user_id = #{id}
</select>
说明:
- userMap是queryUser方法的查询结果的字段映射。
- 从queryUser的查询结果中取到u_id,作为queryTypeByUid的查询条件。
- javaType是指定IUser实体中、types的类型。
- column是指定IUser的主键字段。
测试及结果:
@Test public void testQueryUserById(){ userMapper.queryUser(81); }
==> Preparing: select u_id,user_name from t_user where u_id =?
==> Parameters: 81(Integer)
<== Columns: u_id, user_name
<== Row: 81, 李四
====> Preparing: select type_name from t_type where user_id = ?
====> Parameters: 81(Integer)
<==== Columns: type_name
<==== Row: 诗歌
<==== Row: 小说
<==== Row: 散文
<==== Total: 3
<== Total: 1
处理方式二:查询结果嵌套
将用户表join 类型表,对查询得到的结果进行字段映射
<resultMap id="userMap2" type="com.example.demo.domain.entity.IUser">
<result property="userName" column="user_name"/>
<collection property="types" javaType="ArrayList" ofType="IType">
<result property="name" column="type_name"/>
</collection>
</resultMap>
<select id="queryUser2" resultMap="userMap2">
select tu.user_name,tt.type_name
from t_user tu join t_type tt on tu.u_id=tt.user_id
and tu.u_id=#{uId}
</select>
说明:
- ofType指定list中属性的类型。
测试及结果:
@Test public void testQueryUserById(){ userMapper.queryUser2(81); }
==> Preparing: select tu.user_name,tt.type_name from t_user tu join t_type tt on tu.u_id=tt.user_id and tu.u_id=?
==> Parameters: 81(Integer)
<== Columns: user_name, type_name
<== Row: 李四, 诗歌
<== Row: 李四, 小说
<== Row: 李四, 散文
<== Total: 3
多对一:查询指定类型的创建者
在ITypeMapper.java接口创建查询类型的方法,并在ITypeMapper.xml中实现这个接口方法。
/** * 查询指定文章及创建它用户 */ IType queryType(Integer tId);
关联-association(n:1)的使用
处理方式一:查询条件嵌套】
先查类型表,得到userId,再拿userId去用户表找用户名。
<resultMap id="typeMap" type="com.example.demo.domain.entity.IType"> <result property="name" column="type_name"/> <association property="user" javaType="IUser" column="user_id" select="queryUserById"> <result property="userName" column="user_name"/> </association> </resultMap> <resultMap id="userMap" type="com.example.demo.domain.entity.IUser"> <result property="userName" column="user_name"/> </resultMap> <select id="queryUserById" resultMap="userMap"> select user_name from t_user where u_id =#{userId} </select> <select id="queryType" resultMap="typeMap"> select user_id,type_name from t_type where t_id =#{tId} </select>
测试及结果:
@Test public void testQueryTypeById(){ typeMapper.queryType(10); }
==> Preparing: select user_id,type_name from t_type where t_id =?
==> Parameters: 10(Integer)
<== Columns: user_id, type_name
<== Row: 81, 诗歌
====> Preparing: select user_name from t_user where u_id =?
====> Parameters: 81(Long)
<==== Columns: user_name
<==== Row: 李四
<==== Total: 1
<== Total: 1
处理方式二:查询结果嵌套
类型表和用户表关联。根据类型ID来取值;
<resultMap id="typeMap2" type="com.example.demo.domain.entity.IType"> <result property="name" column="type_name"/> <association property="user" javaType="IUser" column="user_id"> <result property="userName" column="user_name"/> </association> </resultMap> <select id="queryType2" resultMap="typeMap2"> select tt.type_name,tu.user_name from t_user tu join t_type tt on tu.u_id = tt.user_id and tt.t_id =#{tId} </select>
测试及结果:
@Test public void testQueryTypeById(){ typeMapper.queryType2(10); }
==> Preparing: select tt.type_name,tu.user_name from t_user tu join t_type tt on tu.u_id = tt.user_id and tt.t_id =?
==> Parameters: 10(Integer)
<== Columns: type_name, user_name
<== Row: 诗歌, 李四
<== Total: 1
当然也可通过代码角度来解决
类似查询条件嵌套、但是在程序是两个相互独立的方法。是实现功能解耦的一个思路。
比如:查询user_name="李四"创建的文章类型名称。
1) 先通过用户表访问表拿到用户ID。
2)通过用户ID去访问类型表取到类型名称。
根据提供的条件查询用户
/** *根据提供的条件查询用户 */ IUser queryUser3(IUser user);
<resultMap id="userMap4" type="com.example.demo.domain.entity.IUser"> <result property="uId" column="u_id"/> <result property="userName" column="user_name"/> </resultMap> <select id="queryUser3" resultMap="userMap4" parameterType="com.example.demo.domain.entity.IUser"> select user_name, u_id from t_user <where> <if test="userName != null"> and user_name = #{userName} </if> <if test="uId !=null"> and u_id =#{uId} </if> </where> </select>
根据提供的条件查询文章类型
/** * 根据提供的条件查询文章类型 */ List<IType> queryType3(IType type);
<resultMap id="typeMap3" type="com.example.demo.domain.entity.IType"> <result property="name" column="type_name"/> <result property="userId" column="user_id"/> </resultMap> <select id="queryType3" resultMap="typeMap3" parameterType="com.example.demo.domain.entity.IType"> select type_name,user_id from t_type <where> <if test="userId !=null"> and user_id = #{userId} </if> <if test="name !=null"> and type_name = #{name} </if> <if test="tId !=null"> and t_id =#{tId} </if> </where> </select>
测试及结果:
/** * 输出李四及其创建的文章类型 */ @Test public void testQueryUserByName(){ // 1、 先通过用户名查询用户信息---->得到用户ID IUser queryUser = new IUser(); queryUser.setUserName("李四"); IUser user = userMapper.queryUser3(queryUser); // 2、通过用户ID得到该用户创建的所有类型 IType type = new IType(); type.setUserId(user.getUId()); List<IType> types = typeMapper.queryType3(type); List<String> strings = new ArrayList<>(); types.forEach(item->{ strings.add(item.getName()); }); //3、输出 HashMap<String,List<String>> userMap = new HashMap<>(); userMap.put(user.getUserName(),strings); System.out.println("userMap:"+userMap); }
执行SQL:
==> Preparing: select user_name, u_id from t_user WHERE user_name = ?
==> Parameters: 李四(String)
<== Columns: user_name, u_id
<== Row: 李四, 81
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1de08775]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5b895e76] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1948456514 wrapping com.mysql.cj.jdbc.ConnectionImpl@3e998033] will not be managed by Spring
==> Preparing: select type_name from t_type WHERE user_id = ?
==> Parameters: 81(Integer)
<== Columns: type_name
<== Row: 诗歌
<== Row: 小说
<== Row: 散文
<== Total: 3
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5b895e76]结果:
userMap:{李四=[诗歌, 小说, 散文]}
/** * 输出编号为10的类型名称及其创建者 */ @Test public void testQueryTypeByTId(){ // 1、先访问类型表拿到user_id IType queryType = new IType(); queryType.setTId(10); List<IType> types = typeMapper.queryType3(queryType); if(!CollectionUtils.isEmpty(types)){ IType type = types.get(0); IUser queryUser = new IUser(); queryUser.setUId(type.getUserId()); // 2、再访问用户表拿到用户信息 IUser user = userMapper.queryUser3(queryUser); // 3、输出 HashMap<String, String> typeMap = new HashMap<>(); typeMap.put(type.getName(),user.getUserName()); System.out.println("typeMap:"+typeMap); } }
==> Preparing: select type_name,user_id from t_type WHERE t_id =?
==> Parameters: 10(Integer)
<== Columns: type_name, user_id
<== Row: 诗歌, 81
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1cc93da4]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@64688978] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1297242263 wrapping com.mysql.cj.jdbc.ConnectionImpl@433ae0b0] will not be managed by Spring
==> Preparing: select user_name, u_id from t_user WHERE u_id =?
==> Parameters: 81(Integer)
<== Columns: user_name, u_id
<== Row: 李四, 81
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@64688978]
typeMap:{诗歌=李四}
放在map中是为便于理解,实际情况直接通过对应的的setter方法给属性赋值,前端拿到对象后、或取List中的字段、或取对应属性的值。