复杂的SQL条件
概述
什么是 Nutz.Dao 中的复杂SQL条件
- 对于 Nutz.Dao 来说,它本质上就是将你的 Java 对象转化成 SQL,然后交给 JDBC 去执行。
- 而 SQL 中,当执行数据删除和查询操作时,最常用的就是 WHERE 关键字。
- WHERE 关键字后面的就是所谓的复杂查询条件
Nutz.Dao 将如何如何使用这个条件
- Dao 接口的 clear 方法和 query 方法的第二个参数,就是为了生成 WHERE 后面那段字符串设计的
- 这个参数是一个 org.nutz.dao.Condition 接口的实现类
- 通过该接口的 toSql(org.nutz.dao.entity.Entity) 方法, Nutz.Dao 将获得 WHERE 后面那段字符串
- 当然也包括 ORDER BY
Condition 接口
- 这个接口只有一个方法 toSql(Entity entity)
- 这个方法带一个参数 org.nutz.dao.entity.Entity
- 通过这个参数,实现者可以获得当前需要操作的实体的配置信息
- 当然,如果你不需要的话,你可以不理睬这个参数
- Nutz.Dao 会将 toSql(Entity entity) 的返回直接拼接到SQL 的 WHERE 关键字后面
- 如果你返回的字符串以 WHERE 或者 ORDER BY 开头,它会直接使用,否则会补上一个 WHERE 关键字
- 这个判断会忽略前后空白以及大小写
Nutz 给你的快速实现
- 如果你的数据库字段被假设不会发生变化,用直接硬编码是个很好的选择
- 如果在开发期,你的数据库字段变化非常频繁,用 Cnd 工具类则是更好的选择
直接硬编码
最简单直接的方法就是直接输出 WHERE 关键字后面的 SQL 代码了。比如查询一个 Person 对象
List<Person> crowd = dao.query(Person.class, Cnd.wrap("name LIKE 'J%' AND age>20"), null);
这句话,就会将所有名称以 J 开头,并且年龄超过20岁的人全部查询出来。参看 Nutz.Dao 入门 针对 Person 对象的描述,实际上,上面那句话执行的 SQL 代码为:
SELECT * FROM t_person WHERE name LIKE 'J%' AND age>20;
当然你要是写
Cnd.wrap("name LIKE 'J%' AND age>20 ORDER BY name ASC");
就会按照 name 字段排序。
一个友好的工具类 -- Cnd
有些情况,数据库中的字段同 Java 对象中的字段并不同名, 所以就需要给 Java 字段上的数据库字段注解加上参数 @Column("数据库字段名") 如果你通过 Cnd.wrap() 硬编码某个字段,那么当这个字段数据库字段名发生改变时,你就需要改动很多。 因此你希望仅仅将对于数据库的变动限制在 Java 对象的源文件里 所以 Nutz 提供了 Cnd.where() 方法
Condition c = Cnd.where("age",">",30).and("name", "LIKE", "%K%").asc("name").desc("id");
这个条件将生成 SQL
WHERE age>30 AND name LIKE '%K%' ORDERBY name ASC, id DESC
你也可以嵌套表达式
SqlExpressionGroup e1 = Cnd.exps("name", "LIKE", "P%").and("age", ">", "20"); SqlExpressionGroup e2 = Cnd.exps("name", "LIKE", "S%").and("age", "<", "30"); Condition c = Cnd.where(e1).or(e2).asc("name");
这个条件将生成 SQL
WHERE (name LIKE 'P%' AND age>'20') OR (name LIKE 'S%' AND age<'30') ORDER BY name ASC
拼装更加复杂的条件
上面的例子的 Cnd.where 函数,在大多数情况下可以快速的生成一个简单的查询条件。但是,如果查询条件非常复杂, 用它可能就比较费劲了。是的,它的设计初衷就是 "查询条件应该一行搞定"。
有些时候,查询条件很复杂,一行确实搞不定,怎么办?Nutz-1.b.38 以后,提供了 Criteria 接口,它继承自 Condition 接口,它的设计目的有两个:
- 让程序员更容易的拼装复杂逻辑的条件
- 让生成的 SQL 可以被参数化,更好的支持 PreparedStatement
这个接口的使用也很简单,它基本符合 "IDE 的所见即所得" 接口设计原则。 就是说,如果你的 IDE 有智能提示的话, 你使用这个接口是不需要文档的。
// 创建一个 Criteria 接口实例 Criteria cri = Cnd.cri(); // 组装条件 if(...){ cri.where().andIn("id", 3,4,5).andIn("name", "Peter", "Wendal", "Juqkai"); }else if(...){ cri.where().andLT("id", 9); } if(...){ cri.where().andLike("name", "%A%"); } cri.getOrderBy().asc("name").desc("id"); // 执行查询 List<MyObj> list = dao.query(MyObj.class, cri, null);
Criteria 的 where() 函数返回的是 SqlExpressionGroup,主要由它来提供各种 SQL 条件的组合方法。 这里需要给出一点提示,比如方法名 andGT,表示的是 andGreatThan,即 "大于" 的意思,同理:
- LT : 小于 (LessThan)
- GTE : 大于等于 (GreatThanEqual)
- LTE : 小于等于 (LessThanEqual)