论坛首页 Java企业应用论坛

“write less,do more” Hibernate下的JQuery --->HQuery

浏览 19608 次
该帖已经被评为良好帖
作者 正文
   发表时间:2009-04-02   最后修改:2009-04-03
    但凡所有程序员都有一个希望,那就是用最少的代码完成最多的事情,而热门的语言,流行的框架也一直在这方面做出了颇多的努力。“write less,do more”这是JQuery 的口号,熟悉他的朋友们都知道他的方便之处,而在Hibernate中,我们能不能以最少的代码做最多的事情呢?有的人也许会说 Hibernate已经很方便了,面向对象的持久化操作,强大的级联,等等,但是我们能不能让他再简单一点呢?我的回答:能!
    最长见的Hibernate使用,最简单的需求如下:
    有一张员工表【HR_EMPLOYEE】
现在需要查询HR_EMPLOYEE表里USE_YN 字段值为Y的然后把他变更为N 通常大家的做法也许会象下面这样:
查询方法
public List<HrEmployee> getHrEmployeeListByUse(){
	DetachedCriteria dc=DetachedCriteria.forClass(SysEmployee.class);
	dc.add(RestrictionBuild.eq("useYn", "Y"));
        return this.sysEmployeeDao.findByCriteria(dc);
}


public void updateHrEmployeeUse(){
       List<HrEmployee> empList=this.getHrEmployeeListByUse();
       if(empList!=null&&!empList.isEmpty){
          for(HrEmployee employee:empList){
              employee.setUseYn("N");
              this.sysEmployeeDao.update(employee);
          }
        }
}

然后在action里调用这个Service的updateHrEmployeeUse()方法实现上面的需求,(而且这还有一个批量更新的问题 一条SQL语句可以实现的 现在会出现N*2条SQL)
好了,举了点以前的例子,现在来说说HQuery到底是个什么东西,能怎么帮我们呢,就按上面的例子 看看HQuery怎么写的 代码如下:
$($eq("useYn","Y")).attr(HrEmployee.class,"useYn","N").save();

看见$了没有,没错 JAVA里也是可以用$做类名 方法名的,其他特殊字符则不行,我来解释一下HQuery这段代码里实际有什么操作
首先HQuery需要以选择器(HQuerySelector)进行构造,如果构造方法参数为null则无条件进行全表查询,HQuerySelector无需大家实例 只需要调用以$开头的方法即可构造 上面使用$eq()方法表示构造的选择器使用eq逻辑进行匹配,还有其他方法$gt(),$ge(),$lt(),$le(),$like(),$or(),$and(),$avg(),$max(),$count(),$min(),$distinct(),
$countDistinct(),$order()太多了 写不过来,但是只要加进去构造方法 即可生效。
$($eq("useYn","Y"))//完成选择器的注入 

$($eq("useYn","Y")).attr(HrEmployee.class,"useYn","N")//通过选择器 加载对象 并把useYn属性赋予N值
//attr会自动判断是否需要迭代  

$($eq("useYn","Y")).attr(HrEmployee.class,"useYn","N").save();
//将加载的全部对象的useYn属性赋予N值以后进行保存,注意 此处如果是单表自属性批量更新 会自动判断只发送一条//SQL语句

如此一来 原来那么多行的代码 用HQuery以后一行代码即可实现,从某种概念上来说,有点JQuery的意思,因为我当初设计HQuery时候是按着JQuery来的,因为我很喜欢JQuery 呵呵!
下面再展示一下HQuery还提供了哪些亮点!
以下代码演示了HQuery 支持page分页 && each()方法的迭代 自动将迭代出的对象传至invoke方法提供快速调用
这个each()方法是完全模仿JQuery写的
Page<HrEmployee> empPage=$($eq("useYn","N")).page(HrEmployee.class,0,5);
        List<HrEmployee> empList=empPage.getResultList();
        $(empList).each(new EachAdapter() {
            @Override
            public void invoke(Object o) {
                HrEmployee hrEmployee= (HrEmployee) o;
                System.out.println(hrEmployee.getEmpNameZh());
                System.out.println(hrEmployee.getUseYn());
            }
        });

除了page()方法以外 还提供了.get();.list().array();.value()方法
HrEmployee hrEmployee=$(Long.valueOf(1)).get(HrEmployee.class);
List<HrEmployee> hrEmployeeList=$($eq("useYn","Y")).list(HrEmployee.class);
int count =$($count("id")).returnType(ReturnType.PLAIN).value(HrEmployee.class,Integer.class);
HrEmployee[] hrEmployeeArray=$($eq("useYn","Y")).array(HrEmployee.class);
$($order("id")).list(HrDuty.class);

还有最基本的save() delete()方法
$(o).save();//保存对象
$(o).delete();//删除对象
//以上两个方法 自动判断 是否是数组以及集合 会自动调用相应的方法


需要说明的一点$()方法传HQuerySelector时候需要从数据库get结果才能进行相关操作
而传object时候 不需要从数据库get结果 因为本身就是结果 进行相关操作
$($eq("useYn,"N")).delete(HrEmployee.class);//删除所以USEYN=N的数据

//又一个模仿JQuery.attr()的例子 一个SET 一个GET 同一个入口
List<String> useYnList=$($eq("useYn","Y")).attr(HrEmployee.class,"useYn");//获取属性 并且封装为List 或者Object[] Object类型为属性在JAVA里的类型 自动转换

接着还有回调
//回调在SAVE执行之前
$(hrEmployee).save(HrDuty.class, new BeforeCallback() {
            @Override
       public void invoke() {
            HrEmployee hrEmployee=this.get(hrEmployee.class);
            hrEmployee.setUseYn("Y");

        }
});
//回调在SAVE执行以后
$(hrEmployee).save(HrDuty.class, new AfterCallback() {
            @Override
       public void invoke() {
            HrEmployee hrEmployee=this.get(HrEmployee .class);
            hrEmployee.setUseYn("Y");

        }
});
//回调在SAVE执行之前&之后
$(hrEmployee).save(HrDuty.class, new AllCallback() {
            @Override
       public void invoke() {
            HrEmployee hrEmployee=this.get(HrEmployee .class);
            hrEmployee.setUseYn("Y");

        }
});

一个复杂的包含OR AND orderby条件的查询
$($order("id",false),$eq("dutyId.useYn","Y"),$alias("dutyId","dutyId"),
$or($like("dutyId.dutyNameZh","a"),
$like("dutyId.dutyNameEn","b"),$like("dutyId.dutyNameKo","c"))).each(
HrEmployee.class,new EachAdapter() {
            @Override
            public void invoke(Object o) {
                HrEmployee hrEmployee= (HrEmployee) o;
                System.out.println(hrEmployee.getEmpNameZh());
                //To change body of implemented methods use File | Settings | File Templates.
            }
        } );

生成SQL如下
select
    this_.id as id1_1_,
    this_.CARD_ID as CARD2_1_1_,
    this_.CREATED as CREATED1_1_,
    this_.CREATEDBY as CREATEDBY1_1_,
    this_.DUTY_ID as DUTY16_1_1_,
    this_.EMP_BECOME_DATE as EMP5_1_1_,
    this_.EMP_DIMISSION_DATE as EMP6_1_1_,
    this_.EMP_ENTRY_DATE as EMP7_1_1_,
    this_.EMP_ID as EMP8_1_1_,
    this_.EMP_NAME_EN as EMP9_1_1_,
    this_.EMP_NAME_KO as EMP10_1_1_,
    this_.EMP_NAME_PY as EMP11_1_1_,
    this_.EMP_NAME_ZH as EMP12_1_1_,
    this_.UPDATED as UPDATED1_1_,
    this_.UPDATEDBY as UPDATEDBY1_1_,
    this_.USE_YN as USE15_1_1_,
    dutyid1_.id as id0_0_,
    dutyid1_.CREATED as CREATED0_0_,
    dutyid1_.CREATEDBY as CREATEDBY0_0_,
    dutyid1_.DISPLAY_ORDER as DISPLAY4_0_0_,
    dutyid1_.DUTY_ID as DUTY5_0_0_,
    dutyid1_.DUTY_NAME_EN as DUTY6_0_0_,
    dutyid1_.DUTY_NAME_KO as DUTY7_0_0_,
    dutyid1_.DUTY_NAME_ZH as DUTY8_0_0_,
    dutyid1_.UPDATED as UPDATED0_0_,
    dutyid1_.UPDATEDBY as UPDATEDBY0_0_,
    dutyid1_.USE_YN as USE11_0_0_
from
    HR_EMPLOYEE this_
inner join
    HR_DUTY dutyid1_
        on this_.DUTY_ID=dutyid1_.id
where
    dutyid1_.USE_YN=?
    and (
        (
            dutyid1_.DUTY_NAME_ZH like ?
            or dutyid1_.DUTY_NAME_EN like ?
        )
        or dutyid1_.DUTY_NAME_KO like ?
    )
order by
    this_.id desc

总的来说 HQuery以JQuery的语法实现了Hibernate的基本的简单的一些操作,也能“write less,do more”
但是因为这个作品是3月29日动工的于昨晚完成,所以有可能会有一些不足,也请各位看完以后留下您的宝贵意见。
批评和建议均可~谢谢。
PS:在HQuery设计初期 差点放弃,就因为多线程下的稳定性原因,还好,在梦种想到如何解决多线程下调用的问题,目前已经圆满解决。希望通过这次发帖 得到大家的意见 然后再次改进,并加入的http://www.iteye.com/topic/232885
这个框架中,guiceSide已经开源了,但是这几天整合进去了Freemarker 与HQuery 将暂停几天开源 等最终修改完成的代码通过测试,再上传googlecode:http://code.google.com/p/guice-side/


/*************************超级无敌分割线*************************************/
/*************************已把jar删除 打包时候存在一点bug 暂时删除 待提供配置文件以后能让大家方便集成时候上传 估计得等周末了 SORRY*************************************/
   发表时间:2009-04-02  
效率惊人啊,3月29日动工,这么快完成。

看了语法。我有一点建议。
引用
$($eq("useYn","Y")).attr(HrEmployee.class,"useYn","N")

建议改为
引用
$(HrEmployee.class,$eq("useYn","Y")).attr("useYn","N")



引用
$($eq("useYn,"N")).delete();

这里似乎没有指定操作的Class,建议改为
引用
$(HrEmployee.class,$eq("useYn,"N")).delete();


1 请登录后投票
   发表时间:2009-04-02  
jasongreen 写道
效率惊人啊,3月29日动工,这么快完成。

看了语法。我有一点建议。
引用
$($eq("useYn","Y")).attr(HrEmployee.class,"useYn","N")

建议改为
引用
$(HrEmployee.class,$eq("useYn","Y")).attr("useYn","N")



引用
$($eq("useYn,"N")).delete();

这里似乎没有指定操作的Class,建议改为
引用
$(HrEmployee.class,$eq("useYn,"N")).delete();




建议改为
$(HrEmployee.class,$eq("useYn","Y")).attr("useYn","N")

这个问题再设计之初我就很头疼,因为我想尽量和JQuery一样 所以在设计的时候就把HrEmployee.class给舍去,在最后的时候,也就是实际操作之时 才进行传递 那么我的构造函数就统一了 也和JQUERY比较接近
而还有一点 在有的时候是不需要Object.class的
比如你传递的就是一个entity
$(empObj).attr("useYn","N")

这时候是无需class的
所以我设计的就是当你传递需要进行数据库加载数据的时候 方法会要求必须要传class,否则可以不传
比如save方法 我后台的方法是这2个 而且类的结构设计的就是当你需要哪个就会只显示哪个方法 不会2个方法一起显示 造成混乱
public void save(Class<? extends IdEntity> entityClass) {
        evaluation(entityClass,-1,-1);
        invoke(Persistent.SAVEORUPDATE);
    }

public void save() {
        invoke(Persistent.SAVEORUPDATE);
    }

这里似乎没有指定操作的Class,建议改为

$(HrEmployee.class,$eq("useYn,"N")).delete();

谢谢,帖代码时候忽略了,其实delete方法这时候必须要求传递class,这时 空的参数方法不存在。
1 请登录后投票
   发表时间:2009-04-02  
欢迎竞争。我的仓库猫框架也是用来简化查询的。大家共同努力,让那些丑陋的代码都进垃圾箱吧。
0 请登录后投票
   发表时间:2009-04-02  
zhenjia 写道

这个问题再设计之初我就很头疼,因为我想尽量和JQuery一样 所以在设计的时候就把HrEmployee.class给舍去,在最后的时候,也就是实际操作之时 才进行传递 那么我的构造函数就统一了 也和JQUERY比较接近


我觉得这样设计恰恰不符合JQuery的哲学。
JQuery:  $(查询 or 元素 or 元素[]).操作(操作相关参数)

current HQuery: $(限制条件 or 对象).操作([类名],操作相关参数)

why not : $((类名,限制条件) or 对象 or List or Array).操作(操作相关参数)

class 的存在并不影响与JQuery的相似度,即便是影响也只是形的影响,而不是神的影响。反之则对“神似”有影响。

强烈建议
0 请登录后投票
   发表时间:2009-04-02  
jasongreen 写道
zhenjia 写道

这个问题再设计之初我就很头疼,因为我想尽量和JQuery一样 所以在设计的时候就把HrEmployee.class给舍去,在最后的时候,也就是实际操作之时 才进行传递 那么我的构造函数就统一了 也和JQUERY比较接近


我觉得这样设计恰恰不符合JQuery的哲学。
JQuery:  $(查询 or 元素 or 元素[]).操作(操作相关参数)

current HQuery: $(限制条件 or 对象).操作([类名],操作相关参数)

why not : $((类名,限制条件) or 对象 or List or Array).操作(操作相关参数)

class 的存在并不影响与JQuery的相似度,即便是影响也只是形的影响,而不是神的影响。反之则对“神似”有影响。

强烈建议

发一下$()的构造吧
protected HQueryGet $(Serializable id) {} //接收如id之类的 Long型构造 也就是出常常用到的byId方法
protected HQueryGet $(Serializable id, Selector... selectors) {}//接收id,+Selector
protected HQueryGet $(Selector... selectors) {}//接收Selector
protected HQueryLoad $(IdEntity o) {}//接收object
protected HQueryLoad $(List<? extends IdEntity> o) {}//接收List<Object>

就少了一个你所说的Class.class这个构造参数
看见我前上个返回HQueryGet了吗 代表着他们的相关操作必须传递Class.class 因为这时候没有实际获取到对象所以需要加载
而后2个返回HQueryLoad 则代表 传进去的object就等于实际获取的对象 所以在相关的操作方法就不需要Class.class
之所以这样就想让$()构造起来比较简单 除了id Selector Object 就好 需要用到相关的class时候 在.后续的方法时会提醒的。
0 请登录后投票
   发表时间:2009-04-02  
真是太方便了,以后要写的东西岂不是很少了。
支持楼主。
    
0 请登录后投票
   发表时间:2009-04-02  
dino_zhang 写道
我是来当托的。javaeye回帖竟然要先做测试。
先看看。

托????????我可没花钱请托啊
呵呵
0 请登录后投票
   发表时间:2009-04-02  
dino_zhang 写道

我是来当托的。javaeye回帖竟然要先做测试。 先看看。

服了,就是当拖的也不用写这么明白吧。
0 请登录后投票
   发表时间:2009-04-02  
魔力猫咪 写道
欢迎竞争。我的仓库猫框架也是用来简化查询的。大家共同努力,让那些丑陋的代码都进垃圾箱吧。

呵呵 我大概看了一下你的 基于HQL 是吧
我的里面没有HQL
都是criteria实现的。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics