过滤字段

Jul 10, 2017 10:38:44 AM

为什么需要过滤字段

例如insert时需要忽略某个特定属性, update时只更新某些属性, 查询时需要跳过大字段等。

FieldFilter/FieldMatcher提供细致的过滤选项,包括:

  • 黑名单(locked)
  • 白名单(actived)
  • 忽略空值(ignoreNull)
  • 忽略数值0(ignoreZero)
  • 忽略日期属性(ignoreDate)
  • 忽略空字符串(ignoreBlankStr)
  • 忽略数值型主键(ignoreId), 仅insert操作有效
  • 忽略字符型主键(ignoreName), 仅insert操作有效
  • 忽略复合主键(ignorePk), 仅insert操作有效
    FieldFilter是FieldMatcher的包装,相当于Map<Class, FieldMatcher>

    黑名单和白名单,均为正则表达式,匹配是Java属性名!!

    ignoreNull/ignoreZero/ignoreDate/ignoreBlankStr对insert(pet)无效,有多参数的insert替代.

如何过滤字段

如下代码,将只更新 Pet 的 id 和 name 属性:

  1. // 第二个参数是正则表达式
  2. FieldFilter ff = FieldFilter.create(Pet.class, "^id|name$");
  3. ff.run(new Atom() {
  4. public void run() {
  5. Pet pet = dao.fetch(Pet.class, 24);
  6. pet.setName("ABC");
  7. pet.setNickname("XiaoBai");
  8. dao.update(pet);
  9. }
  10. });
  11. // 或者
  12. Daos.ext(dao, ff).update(pet);

以下代码, 将只查询id和name属性

  1. FieldFilter ff = FieldFilter.create(Pet.class, "^id|name$");
  2. Pet pet = ff.run(new Molecule() {
  3. public void run() {
  4. setObj(dao.fetch(Pet.class, "ABC"));
  5. }
  6. });
  7. // 或者用Daos.ext
  8. Pet pet = Daos.ext(dao, ff).fetch(Pet.class, "ABC");

字段过滤器的原理

字段过滤,不过是要在一个地方记录一下下面两个信息:

  • 对什么实体
  • 过滤哪些字段
    并且它希望 Nutz.Dao 自行能获取到这些信息。当然,ThreadLocal 就是一个很好的选择。实际上,你如果看看 FieldFilter 里面的方法,你其实就能猜到。为了能为多个实体保存字段过滤配置信息,它实际上在ThreadLoacal 里保存了自身的一个实例,同时,它自己有一个私有的 Map<Class<?>, FieldMatcher>,具体的,你可以看 FieldFilter 这个类的定义:
  1. public class FieldFilter {
  2. ...
  3. private static ThreadLocal<FieldFilter> FF = new ThreadLocal<FieldFilter>();
  4. ...
  5. private Map<Class<?>, FieldMatcher> map;
  6. ...
  7.  

而且既然在 ThreadLocal 设置了数据,它就不得不考虑如何让你清除这个数据。因此,它的写法也保证了你一定会清掉你的数据了。

  1. FieldFilter ... run(new Atom(){ // <-- 开始将自身加入 ThreadLocal
  2. public void run(){
  3. // 这里是你的代码,你的 Dao 调用都会得到 ThreadLocal 中你对于实体字段过滤的设置
  4. }
  5. }); // <-- run 方法结束前,会从 ThreadLocal 清除自身

字段过滤器的创建

下面是一个最简单和常用的例子:

  1. FieldFilter.create(Pet.class, "^id|name$").run(new Atom(){
  2. public void run(){
  3. // TODO 你的 DAO 操作代码
  4. }
  5. });
  • 这样,无论你查询或者更新等操作,对 Pet 这个实体只会针对能被正则表达式 "id|name" 匹配的字段进行操作
    • 实际上,上例的正则表达式表示: 所有包括 id 和 name 字符的字段
  • 如果你想仅仅让 id 和 name 字段受到匹配,你的正则表达式最好写的严格一些,比如 "^id|name$"
  • 当然,SQL 的条件部分不会受到字段过滤器的影响
    如果你读完上面的介绍,你应该就很了解字段过滤器如何使用了,但是你可能还有个几个小疑问:

  • 如果我字段比较多怎么办呢?

  • 如果我想忽略所有之为空的字段怎么办呢?
  • 如果我想同时为多个实体设置字段过滤怎么办呢?

忽略少数字段

  1. FieldFilter.locked(Pet.class, "^last|age$").run(new Atom(){
  2. public void run(){
  3. // TODO 你的 DAO 操作代码
  4. }
  5. });

忽略空值

  1. FieldFilter.create(Pet.class, true).run(new Atom(){
  2. public void run(){
  3. // TODO 你的 DAO 操作代码
  4. }
  5. });

保留几个字段且忽略空值

  1. FieldFilter.create(Pet.class,"^id|name|age|last$", true).run(new Atom(){
  2. public void run(){
  3. // TODO 你的 DAO 操作代码
  4. }
  5. });

忽略少数字段且忽略空值

  1. FieldFilter.create(Pet.class, null, "^age|last$", true).run(new Atom(){
  2. public void run(){
  3. // TODO 你的 DAO 操作代码
  4. }
  5. });

为多个实体设置字段过滤

  1. FieldFilter.create(Pet.class, true)
  2. .set(Master.class, "^id|name$")
  3. .run(new Atom(){
  4. public void run(){
  5. // TODO 你的 DAO 操作代码
  6. }
  7. });

使用FieldMatcher创建复杂规则

  1. FieldMatcher fm = FieldMatcher.make(actived, locked, ignoreNull,
  2. ignoreZero, ignoreDate,
  3. ignoreId,
  4. ignoreName,
  5. ignorePk);
  6. FieldFilter ff = FieldFilter.create(Pet.class, fm);

无需匿名内部类的写法

从1.b.51开始支持不使用匿名内部类的方法, Daos.ext方法. 该方法有两个变种, 分别支持字段过滤和动态表名.

示例

  1. //原写法
  2. FieldFilter.create(Pet.class, "^id|name$").run(new Atom(){
  3. public void run(){
  4. dao.update(pet); // 这里的pet必须是final
  5. }
  6. });
  7. // 新的写法
  8. Daos.ext(dao, FieldFilter.create(Pet.class, "^id|name$")).update(pet);
  9. // ext方法会返回一个Dao实例,是对原有dao对象的封装

FieldFilter实例及Daos.ext返回的Dao实例,可重复使用,均为线程安全的.

本页面的文字允许在知识共享 署名-相同方式共享 3.0协议GNU自由文档许可证下修改和再使用。

原文: http://nutzam.com/core/dao/field_filter.html