缘由
最近使用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());
为了避免无嵌套的多条件查询也会被括号包裹,使用andWhere
和orWhere
来追加条件
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。