mybatis-generator優化:SqlExample

緣由

最近使用mybatis接觸到了mybatis-generator,感覺蠻好用的,但是example部分限制較大:

  • 爲每一個實體類構建了一個example類,代碼量冗餘度極高
  • 條件或只能構建成(A and B) or (C and D)的形式
  • 指定查詢字段爲setFields("id, name"),即參數爲字符串(雖然fields是通過插件添加上去的)
  • 設置order by子句爲setOrderByClause("create_time desc"),參數依然爲字符串

我強調後兩條參數爲字符串,是因爲這種設計不太理想:

  • 一旦數據庫字段變更,重新生成文件後手寫的字段名是改不過來的
  • 手寫字段名稱沒有代碼提示易出現錯誤

看來generator的example是需要改進的。

方針

邊界:單表操作

example類只爲單表操作設計,複雜sql語句在mapper中編寫。若複雜的sql語句使用代碼編寫會帶來很大的複雜度,得不償失。

目的:全代碼提示

最大限度保證使用example過程中,不出現字段名稱的字符串形式,不需要修改已經編寫的代碼或有代碼提示錯誤。

期望

setDistinct

BrandQuery brandQuery = new BrandQuery();
brandQuery.setDistinct(true);

assertTrue(brandQuery.isDistinct());

其實BrandQuery繼承了SqlExample,建議使用SqlExample<Brand>替換BrandQuery

SqlExample<Brand> example = new SqlExample<Brand>().setDistinct(true);

assertTrue(example.isDistinct());

setFields

setFields用於設置查詢字段,每次調用會覆蓋上次的值。

SqlExample<Brand> example = new SqlExample<Brand>()
        .setFields(Brand.ID, Brand.FIRST_CHAR.as("first"));

assertEquals("id, first_char as first", example.getFields());

使用addFields用於對字段進行追加

SqlExample<Brand> example = new SqlExample<Brand>()
        .setFields(Brand.ID)
        .addFields(Brand.FIRST_CHAR.as("first"));

assertEquals("id, first_char as first", example.getFields());

使用FastExample寫法

SqlExample<Brand> example =
        FastExample.fields(Brand.ID).addFields(Brand.FIRST_CHAR.as("first"));

assertEquals("id, first_char as first", example.getFields());

orderBy

orderBy用於設置order by子句,每次調用會覆蓋上次的值。

SqlExample<Brand> example = new SqlExample<Brand>()
        .orderBy(Brand.FIRST_CHAR.desc(), Brand.NAME.asc());

assertEquals("first_char desc, name asc", example.getOrderByClause());

使用andOrderBy用於對排序字段進行追加

SqlExample<Brand> example = new SqlExample<Brand>()
        .orderBy(Brand.FIRST_CHAR.desc())
        .andOrderBy(Brand.NAME.asc());

assertEquals("first_char desc, name asc", example.getOrderByClause());

使用FastExample寫法

SqlExample<Brand> example =
        FastExample.orderBy(Brand.FIRST_CHAR.desc()).andOrderBy(Brand.NAME.asc());

assertEquals("first_char desc, name asc", example.getOrderByClause());

where

where用於設置條件查詢,每次調用會覆蓋上次的值。

簡單查詢

SqlExample<Brand> example = new SqlExample<Brand>().where(Brand.ID.equal(1L));

List<Criterion<Brand>> criterionList = example.getCriterionList();

assertEquals("id = ", criterionList.get(0).getPrefix());
assertEquals(1L, criterionList.get(0).getValue());

使用FastExample寫法

SqlExample<Brand> example = FastExample.where(Brand.ID.equal(1L));

List<Criterion<Brand>> criterionList = example.getCriterionList();

assertEquals("id = ", criterionList.get(0).getPrefix());
assertEquals(1L, criterionList.get(0).getValue());

字段與字段間的條件

SqlExample<Brand> example = new SqlExample<Brand>();
example.where(Brand.NAME.equal(Brand.FIRST_CHAR));

List<Criterion<Brand>> criterionList = example.getCriterionList();

assertEquals("name = first_char", criterionList.get(0).getPrefix());

使用表達式進行多條件查詢

SqlExample<Brand> example = new SqlExample<Brand>().where(c -> c
        .and(Brand.NAME.like("%abc%"))
        .and(Brand.FIRST_CHAR.like("%A%")));
        
List<Criterion<Brand>> criterionList = example.getCriterionList();

assertEquals("(", criterionList.get(0).getPrefix());
assertEquals("name like ", criterionList.get(1).getPrefix());
assertEquals("%abc%", criterionList.get(1).getValue());
assertEquals(" and ", criterionList.get(2).getPrefix());
assertEquals("first_char like ", criterionList.get(3).getPrefix());
assertEquals("%A%", criterionList.get(3).getValue());
assertEquals(")", criterionList.get(4).getPrefix());

爲了避免無嵌套的多條件查詢也會被括號包裹,使用andWhereorWhere來追加條件

SqlExample<Brand> example = new SqlExample<Brand>()
        .andWhere(Brand.NAME.like("%abc%"))
        .orWhere(Brand.FIRST_CHAR.like("%A%"));
        
List<Criterion<Brand>> criterionList = example.getCriterionList();

assertEquals("name like ", criterionList.get(0).getPrefix());
assertEquals("%abc%", criterionList.get(0).getValue());
assertEquals(" or ", criterionList.get(1).getPrefix());
assertEquals("first_char like ", criterionList.get(2).getPrefix());
assertEquals("%A%", criterionList.get(2).getValue());

使用表達式進行嵌套條件查詢

SqlExample<Person> example = new SqlExample<Person>().where(c -> c
        .and(c -> c
                .and(Person.AGE.equal(13))
                .or(Person.NAME.like("%abc%")))
        .or(c -> c
                .and(Person.AGE.equal(13))
                .or(Person.NAME.like("%abc%")));

List<Criterion<Person>> criterionList = example.getCriterionList();

assertEquals("(", criterionList.get(0).getPrefix());
assertEquals("age = ", criterionList.get(1).getPrefix());
assertEquals(13, criterionList.get(1).getValue());
assertEquals(" or ", criterionList.get(2).getPrefix());
assertEquals("name like ", criterionList.get(3).getPrefix());
assertEquals("%abc%", criterionList.get(3).getValue());
assertEquals(")", criterionList.get(4).getPrefix());
assertEquals(" or ", criterionList.get(5).getPrefix());
assertEquals("(", criterionList.get(6).getPrefix());
assertEquals("age = ", criterionList.get(7).getPrefix());
assertEquals(13, criterionList.get(7).getValue());
assertEquals(" or ", criterionList.get(8).getPrefix());
assertEquals("name like ", criterionList.get(9).getPrefix());
assertEquals("%abc%", criterionList.get(9).getValue());
assertEquals(")", criterionList.get(10).getPrefix());

真實案例中if判斷進行條件添加

Criteria<Brand> criteria = new Criteria<>();

if(!StringUtils.isNullOrEmpty(searchInput.getName())) {
    criteria.and(Brand.NAME.like("%"+searchInput.getName()+"%"));
}
if(!StringUtils.isNullOrEmpty(searchInput.getFirstChar())) {
    criteria.and(Brand.FIRST_CHAR.like("%"+searchInput.getFirstChar()+"%"));
}

SqlExample<Brand> example = new SqlExample<Brand>().where(criteria);

return brandDao.selectByExample(example);

使用andWhere可以不創建Criteria實例

SqlExample<Brand> example = new SqlExample<Brand>();

if(!StringUtils.isNullOrEmpty(searchInput.getName())) {
    example.andWhere(Brand.NAME.like("%"+searchInput.getName()+"%"));
}
if(!StringUtils.isNullOrEmpty(searchInput.getFirstChar())) {
    example.andWhere(Brand.FIRST_CHAR.like("%"+searchInput.getFirstChar()+"%"));
}

return brandDao.selectByExample(example);

SqlExample支持所有原查詢操作,如下

equal(value)
notEqual(value)
greaterThan(value)
greaterAndEqualThan(value)
lessThan(value)
lessAndEqualThan(value)
isNull()
isNotNull()
in(list)
notIn(list)
between(value1, value2)
notBetween(value1, value2)
like(string)
notLike(string)

引入

文件生成

  • 打開generator_for_sqlexample工程
  • 在工程中打開generatorConfig.xml文件修改配置信息
  • 執行src中的GeneratorSqlmap類入口函數即可生成文件

安裝jar包到本地maven

generator_for_sqlexample工程lib中的mybatis-generator-sqlexample-1.1.jar包需要引入到項目中。

打開命令行工具鍵入並運行下面的命令,將mybatis-generator-sqlexample-1.1.jar包所在位置換成自己包所在的位置。

mvn install:install-file -Dfile=包所在位置\mybatis-generator-sqlexample-1.1.jar -DgroupId=org.mybatis.generator -DartifactId=mybatis-generator-sqlexample -Dversion=1.1 -Dpackaging=jar

顯示BUILD SUCCESS後,就可在自己的maven工程中添加依賴了

<dependency>
    <groupId>org.mybatis.generator</groupId>
    <artifactId>mybatis-generator-sqlexample</artifactId>
    <version>1.1</version>
</dependency>

需要注意的是,要使用mybatis-generator-sqlexample需要將Java語言級別設爲8。

源碼地址:https://github.com/amuliang/generator

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章