2019-12-05 mybatis的discriminator 和 if 如何使用枚举对象作为条件

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


    

  • 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属性作为鉴别字段:


    
        
        
        
        
            
            
                
            
            
                
            
        
    
    ......

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

  • 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)方法转换为字符串以后,再跟 也就是说:

  • 鉴别器认的,是转换为java类型后的值,不是数据库中存储的原始值。
  • case语句的value指定的参照值,是和鉴别属性使用String.toString()处理后的值进行比对

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结果集,必须这样写:


    
        
        
        
        
            
            
                
            
            
                
            
        
    
    ......

因为:

  • 我override了枚举的toString()方法。
  • 假设枚举值是 enumItem,mybatis执行 String.toString(enumItem) 的结果,实际上是enumItem.toString()的结果。

3. mybatis的标签如何使用枚举作为条件

仍然使用上面的OrderCategory作为例子。
假如,我们要在查询中,使用

            

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

            
  • mybatis的动态sql,基于ognl进行描述。
  • 对枚举作为比对值,使用@类名@枚举项来引用。
  • 无论枚举项是 OrderCategory.TimedOrder,还是OrderCategory.TimedOrder(2),其枚举项都是TimedOrder。

你可能感兴趣的:(2019-12-05 mybatis的discriminator 和 if 如何使用枚举对象作为条件)