关系型数据库相关

2019-12-05 mybatis的discriminator

2019-12-05  本文已影响0人  FredWorks

mybatis的discriminator和if的基本使用,就不多说了。mybatis自家官网上的电子书《MyBatis3 教程 中文版》中就有。
但这本书中的描述比较简单,只说了使用基础类型作为条件时的用法。

<discriminator javaType="int" column="draft">
    <case value="1" resultType="DraftPost"/>
</discriminator>
  • column="draft":结果集中的列“draft”的值,用作鉴别器的值
  • javaType="int":该列转换出来的对象中,数据类型是int
  • case value="1":当对象的值是1时,将结果集映射为对象 DraftPost 的实例。

那么问题来了。如果我们使用对象的枚举类型属性作为鉴别器和if的条件时,如何配置?上网百度,也没有一个说这个问题的。干脆扒源代码,才找到答案。
下面通过例子来说明具体做法。

1. 常规枚举作为鉴别器的鉴别属性

首先,下面例子只是为了说明使用枚举作为鉴别器的场景,不讨论模型业务上的合理性。我要映射的模型如下:
枚举 OrderCategory 列举了订单种类;Order 是普通订单,也是特殊订单类型的父类;TimedOrder是计时订单;SiteOrder是场地订单。

/**
 * 订单类型
 * @author FredWorks
 * 2019年12月5日 上午9:23:58
 */
public enum OrderCategory {
    
    /**
     * 普通订单
     */
    NormalOrder,
    
    /**
     * 计时订单
     */
    TimedOrder,
    
    /**
     * 场地订单
     */
    SiteOrder;
}

/**
 * 普通订单
 * @author FredWorks
 * 2019年12月5日 上午9:16:07
 */
public class Order implements Serializable {

    private static final long serialVersionUID = -8779032621915871117L;

    /**
     * 唯一标识
     */
    private String id;

    /**
     * 总价
     */
    private BigDecimal totalPrice;
    
    /**
     * 订单类型
     */
    private OrderCategory orderCategory;

    /**
     * 获取属性  id 的值
     * @return 属性 id 的值
     */
    public String getId() {
        return this.id;
    }

    /**
     * 给属性 id 赋值
     * @param id 将要给属性 id 赋予的值
     */
    public void setId(String id) {
        this.id = id;
    }

    /**
     * 获取属性  totalPrice 的值
     * @return 属性 totalPrice 的值
     */
    public BigDecimal getTotalPrice() {
        return this.totalPrice;
    }

    /**
     * 给属性 totalPrice 赋值
     * @param totalPrice 将要给属性 totalPrice 赋予的值
     */
    public void setTotalPrice(BigDecimal totalPrice) {
        this.totalPrice = totalPrice;
    }

    /**
     * 获取属性  orderCategory 的值
     * @return 属性 orderCategory 的值
     */
    public OrderCategory getOrderType() {
        return this.orderCategory;
    }

    /**
     * 给属性 orderCategory 赋值
     * @param orderCategory 将要给属性 orderCategory 赋予的值
     */
    public void setOrderType(OrderCategory orderCategory) {
        this.orderCategory = orderCategory;
    }
}

/**
 * 计时订单
 * @author FredWorks
 * 2019年12月5日 上午9:27:26
 */
public class TimedOrder extends Order {

    private static final long serialVersionUID = 3426131282358762200L;
    
    /**
     * 消费时长
     */
    private int consumingMinutes;

    /**
     * 获取属性  consumingMinutes 的值
     * @return 属性 consumingMinutes 的值
     */
    public int getConsumingMinutes() {
        return this.consumingMinutes;
    }

    /**
     * 给属性 consumingMinutes 赋值
     * @param consumingMinutes 将要给属性 consumingMinutes 赋予的值
     */
    public void setConsumingMinutes(int consumingMinutes) {
        this.consumingMinutes = consumingMinutes;
    }
}

/**
 * 场地订单
 * @author FredWorks
 * 2019年12月5日 上午9:27:56
 */
public class SiteOrder extends Order {

    private static final long serialVersionUID = -8420951718498548031L;
    
    /**
     * 场地对象唯一标识
     */
    private String siteId;

    /**
     * 获取属性  siteId 的值
     * @return 属性 siteId 的值
     */
    public String getSiteId() {
        return this.siteId;
    }

    /**
     * 给属性 siteId 赋值
     * @param siteId 将要给属性 siteId 赋予的值
     */
    public void setSiteId(String siteId) {
        this.siteId = siteId;
    }
}

如果我们希望在一个mybatis的结果集中,根据orderType的值,决定返回那种类型的Order实例,我们就需要使用orderType属性作为鉴别字段:

<mapper namespace="cn.fredworks.persistence.mybatis.dao.order.IOrderDao">
    <resultMap type="cn.fredworks.model.order.Order" id="orderResultMap">
        <id column="id" property="id" />
        <result column="total_rice" property="totalPrice" />
        <result column="order_category" property="orderCategory" 
            typeHandler="cn.fredworks.persistence.mybatis.typehandler.order.OrderCategoryTypeHandler"/>
        <discriminator javaType="cn.fredworks.model.order.OrderCategory" column="order_category"
                typeHandler="cn.fredworks.persistence.mybatis.typehandler.order.OrderCategoryTypeHandler">
            <case value="NormalOrder" resultType="cn.fredworks.model.order.Order"/>
            <case value="TimedOrder" resultType="cn.fredworks.model.order.TimedOrder"/>
                <result column="consuming_minutes" property="consumingMinutes" />
            </case>
            <case value="SiteOrder" resultType="cn.fredworks.model.order.SiteOrder"/>
                <result column="site_id" property="siteId" />
            </case>
        </discriminator>
    </resultMap>
    ......
</mapper>

我们对比一下使用基础类型作为鉴别字段时的差别,会发现如下几点:

  • javaType="cn.fredworks.model.order.OrderCategory":javaType使用完整的枚举类名
  • column="order_category":列名仍然需要
  • typeHandler="cn.fredworks.persistence.mybatis.typehandler.order.OrderCategoryTypeHandler":多了转换数据库存储类型为java枚举类型的转换器
  • case value="NormalOrder":这里是重点。它使用枚举项的字面值作为case进行比对的值。

实际上,如果我们跟踪mybtais的代码的话,我们会发现在比对时,它先将Order对象的orderCategory属性,用String.toString(value)方法转换为字符串以后,再跟<case value="xxx" 中,value指定的值进行比对。
也就是说:

2. 自定义枚举作为鉴别器的鉴别属性

假如我们的OrderCategory更加复杂一点:

/**
 * 订单类型
 * @author FredWorks
 * 2019年12月5日 上午9:49:14
 */
public enum OrderCategory {

    /**
     * 普通订单
     */
    NormalOrder(1),
    
    /**
     * 计时订单
     */
    TimedOrder(2),
    
    /**
     * 场地订单
     */
    SiteOrder(3);
    
    /**
     * 下标值。
     */
    private int index;
        
    /**
     * 使用下标构造枚举。
     * 构造函数
     * @param index 用于构造枚举的下标。
     */
    private OrderCategory(int index) {
        this.index = index;
    }

    /**
     * 返回当前枚举的下标。
     * @return 返回本枚举的下标值
     */ 
    public int index() {
        return index;
    }

    /**
     * 根据枚举的下标获取对应的枚举。如果没有找到对应的枚举,则返回null。
     * @param index 枚举的下标值
     * @return 根据下标找到的枚举。如果没有匹配的枚举,返回空指针null。
     */ 
    public static OrderCategory indexOf(int index) {
        for (OrderCategory item : OrderCategory.values()) {
            if (item.index == index) {
                return item;
            }
        }

        return null;
    }

    /**
     * 根据枚举的字面值获取对应的枚举。如果没有找到对应的枚举,则返回null。
     * @param name 枚举的字面值
     * @return 根据字面值找到的枚举。如果没有匹配的枚举,返回空指针null。
     */ 
    public static OrderCategory nameOf(String name) {
        for (OrderCategory item : OrderCategory.values()) {
            if (item.name().equals(name)) {
                return item;
            }
        }

        return null;
    }
    
    /**
     * 输出格式为 name(index)
     */
    @Override
    public String toString() {
        return super.toString() + "(" + this.index + ")";
    }
}

此时的mybatis结果集,必须这样写:

<mapper namespace="cn.fredworks.persistence.mybatis.dao.order.IOrderDao">
    <resultMap type="cn.fredworks.model.order.Order" id="orderResultMap">
        <id column="id" property="id" />
        <result column="total_rice" property="totalPrice" />
        <result column="order_category" property="orderCategory" 
            typeHandler="cn.fredworks.persistence.mybatis.typehandler.order.OrderCategoryTypeHandler"/>
        <discriminator javaType="cn.fredworks.model.order.OrderCategory" column="order_category"
                typeHandler="cn.fredworks.persistence.mybatis.typehandler.order.OrderCategoryTypeHandler">
            <case value="NormalOrder(1)" resultType="cn.fredworks.model.order.Order"/>
            <case value="TimedOrder(2)" resultType="cn.fredworks.model.order.TimedOrder"/>
                <result column="consuming_minutes" property="consumingMinutes" />
            </case>
            <case value="SiteOrder(3)" resultType="cn.fredworks.model.order.SiteOrder"/>
                <result column="site_id" property="siteId" />
            </case>
        </discriminator>
    </resultMap>
    ......
</mapper>

因为:

3. mybatis的<if test="">标签如何使用枚举作为条件

仍然使用上面的OrderCategory作为例子。
假如,我们要在查询中,使用 <if test=""来动态拼装查询语句,且test比对的属性,是基本类型,应当这样写:

            <if test="totalPrice >= 60 and totalPrice <= 100">

但如果test比对的属性是枚举类型,则应当这样写:

            <if test="reserveType == @cn.fredworks.model.order.OrderCategory@TimedOrder">
上一篇下一篇

猜你喜欢

热点阅读