鉴别器discriminator - 按字段选择结果集

2024-05-23 22:32

本文主要是介绍鉴别器discriminator - 按字段选择结果集,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


更多博客内容访问只爱吃火龙果,点击了解详情


鉴别器和switch语句

无论是在C语言还是Java里,相信大家都会对switch语句有一定的印象,switch语句是多分支选择语句,即根据不同的字段,选择执行不同的语句,最大的用处就是用来处理多分支选择的场景。以前初学C语言的时候,把多选择结构用多个嵌套的if语句来实现,导致代码可读性低,switch语句正好解决这一代码冗长的问题。这篇日志写的鉴别器,discriminator标签,就是类似switch语句,实现根据不同的字段来选择不同的resultMap进行映射。你可能会有疑问,查询之前我们的实体类和结果集映射不都是事先配置好的吗?字段和属性一一对应,为什么还要有选择不同的结果集映射这一步?原因,有可能查询返回多个不同的结果集,或者利用鉴别器discriminator,你可以选择那些字段能被映射,那些字段屏蔽掉不被映射。下面来看看这个鉴别器的使用场景有哪些。

场景 – 限权管理:选择映射有联系的结果集

使用场景之一,就是限权的管理,例如一个商场的数据库,对于不同的顾客,管理员因为权限问题,可以查询得到的顾客信息不同,有的顾客除了基本信息外,只能被查询出省会和城市信息,而有的顾客,除了基本信息外,只能被查询出年龄和生日信息。如果要实现这样的限权管理,可以在查询映射时,使用discriminator标签,鉴别查询得到的每一条顾客信息中,根据数据库中的权限字段,假设权限为“1”的顾客,除了基本信息外,只能被查询出省会和城市;权限为“2”的顾客,除基本信息,只能被查询出生日和年龄。然后鉴别器discriminator在查询返回时,会根据权限字段“1”和“2”,分别给出不同的结果集映射,对于权限为“1”的顾客信息,使用屏蔽生日和年龄的resultMap来映射,而对于权限为“2”的顾客,则使用给出生日和年龄字段的映射关系的resultMap。下面来简单看一下这个实现:

持久化实体类

public class UserDiscriminator1 {private int id;private String username; //顾客姓名private String gender; //性别private String email; //电子邮件private String province; //省会private String city; //城市public UserDiscriminator1() {}public UserDiscriminator1(int id, String username, String gender, String email, String province, String city) {this.username = username;this.gender = gender;this.email = email;this.province = province;this.city = city;}
// 省略get()和set()方法
}

假设我们有两个实体类,分别代表两类顾客,其中一类顾客,UserDiscriminator1,除了基本信息外,我们的限权只能够查询出他们的省会和城市信息。

public class UserDiscriminator2 {private int id;private String username; //顾客姓名private String gender; //性别private String email; //电子邮件private Date birthday; //生日private int age; //年龄public UserDiscriminator2() {}public UserDiscriminator2(int id, String username, String gender, String email, Date birthday, int age) {this.username = username;this.gender = gender;this.email = email;this.birthday = birthday;this.age = age;}// 省略get()和set()方法
}

第二类顾客,UserDiscriminator2,除了基本信息,我们的限权只能查出他们的生日和年龄。

在两类顾客的实体类中,假设顾客姓名,性别和电子邮件都是可以查询出来的通用信息,其他的一些个人信息,根据限权的不同,得到的顾客信息会不同。接下来看SQL映射配置文件。

映射配置文件

SQL映射配置文件很重要,因为鉴别器discriminator标签就在里面,它会根据字段的不同,选择不同的case指定的映射方式:

<resultMap type="com.mybatis.po.UserDiscriminator" id="userDiscriminatorResultMap1"><id property="id" column="user_id"/><result property="username" column="user_name"/><result property="gender" column="user_gender"/><result property="email" column="user_email"/><discriminator javaType="int" column="user_id"><case value="1" resultType="userDiscriminator1"><result property="province" column="user_province"/><result property="city" column="user_city"/></case><case value="2" resultType="userDiscriminator2"><result property="birthday" column="user_birthday"/><result property="age" column="user_age"/></case></discriminator></resultMap>

可以看到,无论是查询哪一类顾客的信息,他们都共用一个resultMap,里面配置了顾客名,性别以及电子邮件字段的映射配置。接下来,配置我们要根据的字段值,选择不同的case制定的结果集映射。在discriminator标签中,javaType指定了后面比较的字段column的类型,column配置user_id(这是我数据库表中的字段),即根据用户id字段来选择不同的resultMap。在返回的结果集中,每一条记录都会比较它们的用户id,即user_id字段的值,如果值为“1”,则选择相应的case指定的结果集类型UserDiscriminator1(我配置了批量定义别名,所以第一个字母u可以小写)来进行映射,配置了省会province和城市city两个属性的映射关系。如果id为“2”,则选择结果集类型UserDiscriminator2,里面配置了顾客的生日和年龄字段的映射信息。

  在SQL语句中,分别查询两类顾客的通用信息和特殊信息即可:
<select id="queryUserPosition" parameterType="int" resultMap="userDiscriminatorResultMap1">select U.id as user_id, U.username as user_name, U.gender as user_gender, U.email as user_email,U.province as user_province,U.city as user_cityFROM USER U WHERE U.id=#{id}</select><select id="queryUserInfo" parameterType="int" resultMap="userDiscriminatorResultMap1">select U.id as user_id, U.username as user_name, U.gender as user_gender, U.email as user_email,U.birthday as user_birthday,U.age as user_ageFROM USER U WHERE U.id=#{id}</select>

配置好resultMap后,在编写测试用例之前,别忘了在全局配置文件中配置这个mapper文件!

测试用例

接下来我们做两个查询,验证一下这个结果集的配置,看鉴别器是否真的根据用户id的1和2选择不同的case指定结果集映射。

@Testpublic void TestDiscriminator1() throws IOException {SqlSession sqlSession = dataConn.getSqlSession();UserDiscriminator1 result1 = sqlSession.selectOne("queryUserPosition", 1);System.out.println("姓名:" + result1.getUsername());System.out.println("性别:" + result1.getGender());System.out.println("电子邮件:" + result1.getEmail());System.out.println("所在省会:" + result1.getProvince());System.out.println("所在城市:" + result1.getCity());UserDiscriminator2 result2 = sqlSession.selectOne("queryUserInfo", 2);System.out.println("姓名:" + result2.getUsername());System.out.println("性别:" + result2.getGender());System.out.println("电子邮件:" + result2.getEmail());SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");System.out.println("顾客生日:" + sdf.format(result2.getBirthday()));System.out.println("顾客年龄:" + result2.getAge());sqlSession.close();}

在测试用例中我们分别查询id为1和2的顾客,并在结果集中输出顾客的“通用”信息,姓名性别和电子邮件,以及不同结果集映射的信息,如果前面配置正确,我们可以在result1实例中正确获得并输出顾客的省会和城市信息,result2同理:
在这里插入图片描述

可以看到,映射成功,id=“1”对应的结果集类型UserDiscriminator1实体result1中我们映射的是顾客的省会和城市信息。而id=“2”对应的结果集类型UserDiscriminator2实体result2中,我们映射的是顾客的生日和年龄信息,它们都分别成功地输出了。

引用外部resultMap的配置

上面的例子,我们在鉴别器discriminator标签中,我么指定不同case的映射结果集类型resultType,并把不同的映射关系result标签配置在不同的case标签里。我们也可以引用外部的resultMap,像配置association标签和collection标签那样:

<!-- 引用外部resultMap配置 --><resultMap type="com.mybatis.po.UserDiscriminator" id="userDiscriminatorResultMap2"><id property="id" column="user_id"/><result property="username" column="user_name"/><result property="gender" column="user_gender"/><result property="email" column="user_email"/><discriminator javaType="int" column="user_id"><case value="1" resultMap="userResultMap1"/><case value="2" resultMap="userResultMap2"/></discriminator></resultMap>

case标签中,我们直接指定使用外部的结果集resultMap来进行映射,不用在标签里指定结果集的实体类型,并一个一个地配置。

外部的resultMap:

<resultMap id="userResultMap1" type="com.mybatis.po.UserDiscriminator1"/><result property="province" column="user_province"/><result property="city" column="user_city"/></resultMap><resultMap id="userResultMap2" type="com.mybatis.po.UserDiscriminator2"/><result property="birthday" column="user_birthday"/><result property="age" column="user_age"/></resultMap>

可以说是把这些一个一个的字段和属性映射配置在了外面。不过这种配置方法,有一点要注意的是,和C或Java中的switch语句有点不同(除非在switch中每一个case最后都加上break),鉴别器discriminator一旦选择了一个结果集映射后,其余不符合的case指定的结果集(指外部的resultMap)都会被忽略掉!看回上面的配置:

<!-- 引用外部resultMap配置 --><resultMap type="com.mybatis.po.UserDiscriminator" id="userDiscriminatorResultMap2"><id property="id" column="user_id"/><result property="username" column="user_name"/><result property="gender" column="user_gender"/><result property="email" column="user_email"/><discriminator javaType="int" column="user_id"><case value="1" resultMap="userResultMap1"/><case value="2" resultMap="userResultMap2"/></discriminator></resultMap>

也就是说,虽然我们一开始制定了username,gender以及email的映射关系,但是在discriminator中,如果选中了其中一个case指定的外部resultMap,那么在结果集映射时就会使用这个外部的resultMap,其他的结果映射都会被忽略,包括上面的三个通用配置。这是要注意的一点,使用的测试用例和上面的一样,关键是看看它的输出结果:

@Testpublic void TestDiscriminator1() throws IOException {SqlSession sqlSession = dataConn.getSqlSession();UserDiscriminator1 result1 = sqlSession.selectOne("queryUserPosition", 1);System.out.println("姓名:" + result1.getUsername());System.out.println("性别:" + result1.getGender());System.out.println("电子邮件:" + result1.getEmail());System.out.println("所在省会:" + result1.getProvince());System.out.println("所在城市:" + result1.getCity());UserDiscriminator2 result2 = sqlSession.selectOne("queryUserInfo", 2);System.out.println("姓名:" + result2.getUsername());System.out.println("性别:" + result2.getGender());System.out.println("电子邮件:" + result2.getEmail());SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");System.out.println("顾客生日:" + sdf.format(result2.getBirthday()));System.out.println("顾客年龄:" + result2.getAge());sqlSession.close();}

使用上面的映射配置,分别做查询,result1对象选中case value=“1”的结果集userResultMap1来映射,可以得到省会和城市信息。Result2对象选中 case value=“2”的结果集userResultMap2来映射,可以得到生日和年龄信息。这两个结果集都是引用外部的,接下来看看运行结果:

可以看到,两个对象输出中,三个通用信息都是null,原因并不是数据为空,而是它们没有得到映射关系,property不知道和哪一个column对应。

那则么办?解决的方法还是有的,如果你想让鉴别器discriminator匹配了结果集后,还能使用上面resultMap的映射关系,可以让这两个外部的resultMap,extends继承鉴别器上面的,含有顾客名,性别和电子邮件映射关系的resultMap:

<resultMap id="userResultMap1" type="com.mybatis.po.UserDiscriminator1" extends="userDiscriminatorResultMap2"><result property="province" column="user_province"/><result property="city" column="user_city"/></resultMap><resultMap id="userResultMap2" type="com.mybatis.po.UserDiscriminator2" extends="userDiscriminatorResultMap2"><result property="birthday" column="user_birthday"/><result property="age" column="user_age"/></resultMap>

这样就可以保留结果集userDiscriminatorResultMap2中的配置映射关系。

级联(嵌套)中的discriminator配置

在关联的嵌套结果集中,我们也可以配置鉴别器,还是上面的例子,例如我们有这样一个实体类:

public class UserDiscriminator {private int id;private String username; //顾客姓名private String gender; //性别private String email; //电子邮件HashMap<String, String> userInfo = new HashMap<String, String>();public UserDiscriminator() {}public UserDiscriminator(int id, String username, String gender, String email, HashMap userInfo) {this.id = id;this.username = username;this.gender = gender;this.email = email;this.userInfo = userInfo;}// 省略get()和set()方法
}

里面嵌套了一个HashMap,用来存放不同的映射结果信息,这样我们就不用创建两个实体类来分别存储两个不同映射结果了。具体来看它们的映射配置:

<!-- 级联,关联的嵌套结果集中配置discriminator --><resultMap type="com.mybatis.po.UserDiscriminator" id="userDiscriminatorResultMap3"><id property="id" column="user_id"/><result property="username" column="user_name"/><result property="gender" column="user_gender"/><result property="email" column="user_email"/><association property="userInfo" javaType="java.util.HashMap"><discriminator javaType="int" column="user_id"><case value="1" resultMap="userResultMap3"/><case value="2" resultMap="userResultMap4"/></discriminator></association></resultMap>

Association标签配置嵌套结果集,javaType是HashMap。discriminator中引用的也是外部的resultMap,这两个resultMap和前面配置的外部resultMap,除了结果集类型不同外,其他配置一样:

<resultMap id="userResultMap3" type="java.util.HashMap"><result property="province" column="user_province"/><result property="city" column="user_city"/></resultMap><resultMap id="userResultMap4" type="java.util.HashMap"><result property="birthday" column="user_birthday"/><result property="age" column="user_age"/></resultMap>

最后来看测试用例的代码:

@Testpublic void TestDiscriminator2() throws IOException {SqlSession sqlSession = dataConn.getSqlSession();UserDiscriminator result1 = sqlSession.selectOne("queryUserPosition", 1);HashMap<String, String> resultMap = result1.getUserInfo();System.out.println("姓名:" + result1.getUsername());System.out.println("性别:" + result1.getGender());System.out.println("电子邮件:" + result1.getEmail());System.out.println("所在省会:" + resultMap.get("province"));System.out.println("所在城市:" + resultMap.get("city"));resultMap.clear();UserDiscriminator result2 = sqlSession.selectOne("queryUserInfo", 2);resultMap = result2.getUserInfo();System.out.println("姓名:" + result2.getUsername());System.out.println("性别:" + result2.getGender());System.out.println("电子邮件:" + result2.getEmail());SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");System.out.println("顾客生日:" + sdf.format(resultMap.get("birthday")));System.out.println("顾客年龄:" + resultMap.get("age"));sqlSession.close();}

测试鉴别器选择不同的结果集映射,得到的结果都可以用同一个实例对象来接收,因为不同映射的结果类型都是HashMap接收。

这篇关于鉴别器discriminator - 按字段选择结果集的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/996602

相关文章

el-select下拉选择缓存的实现

《el-select下拉选择缓存的实现》本文主要介绍了在使用el-select实现下拉选择缓存时遇到的问题及解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录项目场景:问题描述解决方案:项目场景:从左侧列表中选取字段填入右侧下拉多选框,用户可以对右侧

如何选择适合孤独症兄妹的学校?

在探索适合孤独症儿童教育的道路上,每一位家长都面临着前所未有的挑战与抉择。当这份责任落在拥有孤独症兄妹的家庭肩上时,选择一所能够同时满足两个孩子特殊需求的学校,更显得尤为关键。本文将探讨如何为这样的家庭做出明智的选择,并介绍星贝育园自闭症儿童寄宿制学校作为一个值得考虑的选项。 理解孤独症儿童的独特性 孤独症,这一复杂的神经发育障碍,影响着儿童的社交互动、沟通能力以及行为模式。对于拥有孤独症兄

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个?

跨平台系列 cross-plateform 跨平台应用程序-01-概览 cross-plateform 跨平台应用程序-02-有哪些主流技术栈? cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个? cross-plateform 跨平台应用程序-04-React Native 介绍 cross-plateform 跨平台应用程序-05-Flutte

如何选择SDR无线图传方案

在开源软件定义无线电(SDR)领域,有几个项目提供了无线图传的解决方案。以下是一些开源SDR无线图传方案: 1. **OpenHD**:这是一个远程高清数字图像传输的开源解决方案,它使用SDR技术来实现高清视频的无线传输。OpenHD项目提供了一个完整的工具链,包括发射器和接收器的硬件设计以及相应的软件。 2. **USRP(Universal Software Radio Periphera

《数据结构(C语言版)第二版》第八章-排序(8.3-交换排序、8.4-选择排序)

8.3 交换排序 8.3.1 冒泡排序 【算法特点】 (1) 稳定排序。 (2) 可用于链式存储结构。 (3) 移动记录次数较多,算法平均时间性能比直接插入排序差。当初始记录无序,n较大时, 此算法不宜采用。 #include <stdio.h>#include <stdlib.h>#define MAXSIZE 26typedef int KeyType;typedef char In

为什么现在很多人愿意选择做债务重组?债重组真的就这么好吗?

债务重组,起初作为面向优质企业客户的定制化大额融资策略,以其高效周期著称,一个月便显成效。然而,随着时代的车轮滚滚向前,它已悄然转变为负债累累、深陷网贷泥潭者的救赎之道。在此路径下,个人可先借助专业机构暂代月供,经一段时间养护征信之后,转向银行获取低成本贷款,用以替换高昂网贷,实现利息减负与成本优化的双重目标。 尽管债务重组的代价不菲,远超传统贷款成本,但其吸引力依旧强劲,背后逻辑深刻。其一

C语言程序设计(选择结构程序设计)

一、关系运算符和关系表达式 1.1关系运算符及其优先次序 ①<(小于) ②<=(小于或等于) ③>(大于) ④>=(大于或等于 ) ⑤==(等于) ⑥!=(不等于) 说明: 前4个优先级相同,后2个优先级相同,关系运算符的优先级低于算术运算符,关系运算符的优先级高于赋值运算符 1.2关系表达式 用关系运算符将两个表达式(可以是算术表达式或关系表达式,逻辑表达式,赋值表达式,字符

可选择的反思指令微调

论文:https://arxiv.org/pdf/2402.10110代码:GitHub - tianyi-lab/Reflection_Tuning: [ACL'24] Selective Reflection-Tuning: Student-Selected Data Recycling for LLM Instruction-Tuning机构:马里兰大学, Adobe Research领