首先,有两个实体,分别是Client和Trade,它们之间是一对多的关系。
Client类部分代码如下:
@OneToMany(mappedBy="client", cascade={CascadeType.REMOVE} //fetch=FetchType.EAGER ) public Set<Trade> getTrades() { return trades; } public void setTrades(Set<Trade> trades) { this.trades = trades; }
Trade类部分代码如下:
@ManyToOne //@JoinColumn(name="CLIENT_ID") public Client getClient() { return client; } public void setClient(Client client) { this.client = client; }
当我做复合查询即按照trade的date属性和client的id属性去查询时,如果是通过criteria.add(Example)方式,则查询返回的结果是所有trade,查询代码如下:
Criteria tradeCriteria = session.createCriteria(Trade.class); Example tradeExample = Example.create(trade); tradeExample.enableLike(MatchMode.ANYWHERE);//使QBE支持模糊查询 tradeCriteria.add(tradeExample); Criteria clientCriteria = tradeCriteria.createCriteria("client"); if(null != trade.getClient()) { Example clientExample = Example.create(trade.getClient()); clientExample.enableLike(MatchMode.ANYWHERE); clientCriteria.add(clientExample); } clientCriteria.list();
后台打印出的sql语句为:
select this_.id as id1_1_, this_.abst as abst1_1_, this_.amount as amount1_1_, this_.balance as balance1_1_, this_.carriage as carriage1_1_, this_.client_id as client15_1_1_, this_.date as date1_1_, this_.flag as flag1_1_, this_.IS_LOAN as IS8_1_1_, this_.level as level1_1_, this_.packages as packages1_1_, this_.payment as payment1_1_, this_.price as price1_1_, this_.remark as remark1_1_, this_.verify as verify1_1_, client1_.id as id0_0_, client1_.COMPANY_ADDR as COMPANY2_0_0_, client1_.COMPANY_NAME as COMPANY3_0_0_, client1_.FAX as FAX0_0_, client1_.MOBILE_PHONE as MOBILE5_0_0_, client1_.name as name0_0_, client1_.OFFICE_PHONE as OFFICE7_0_0_, client1_.REMARK as REMARK0_0_, client1_.type as type0_0_ from Trade this_ inner join Client client1_ on this_.client_id=client1_.id where (this_.date=?) and (1=1)
如果查询client时,不使用Example,而使用criteria.add(Restrictions.eq())方式,则会查询出满足条件的记录,查询代码如下:
Criteria criteria = session.createCriteria(Trade.class); Example tradeExample = Example.create(trade); tradeExample.enableLike(MatchMode.ANYWHERE);//使QBE支持模糊查询 criteria.add(tradeExample); criteria.addOrder(Order.desc("date")); if(null != trade.getClient()) { criteria.createCriteria("client") .add(Restrictions.eq("id", trade.getClient().getId())); } List<Trade> list = criteria.list();
后台打印的sql语句如下:
select this_.id as id1_1_, this_.abst as abst1_1_, this_.amount as amount1_1_, this_.balance as balance1_1_, this_.carriage as carriage1_1_, this_.client_id as client15_1_1_, this_.date as date1_1_, this_.flag as flag1_1_, this_.IS_LOAN as IS8_1_1_, this_.level as level1_1_, this_.packages as packages1_1_, this_.payment as payment1_1_, this_.price as price1_1_, this_.remark as remark1_1_, this_.verify as verify1_1_, client1_.id as id0_0_, client1_.COMPANY_ADDR as COMPANY2_0_0_, client1_.COMPANY_NAME as COMPANY3_0_0_, client1_.FAX as FAX0_0_, client1_.MOBILE_PHONE as MOBILE5_0_0_, client1_.name as name0_0_, client1_.OFFICE_PHONE as OFFICE7_0_0_, client1_.REMARK as REMARK0_0_, client1_.type as type0_0_ from Trade this_ inner join Client client1_ on this_.client_id=client1_.id where (this_.date=?) and client1_.id=? order by this_.date desc limit ?
可以看到,使用这种方式查询时,在where条件中会有client1_id=?,而使用Example就没有。不知道什么原因,困扰了我好几天了。
虽然可以使用这中方式,解决使用Example查询时的问题,但我想弄明白原因。
刚才试了下查询Client的非主键属性,则查询结果为满足条件的记录。where条件语句中and后面会加上Client的条件,而不是1=1了。
所以,在做复合查询时首先要判断是否为主键查询,主键查询需要区别对待,需要使用userCriteria.add(Restrictions.idEq(id)),我想着也就是为什么会有idEq这个方法的原因吧,而且如果只是主键查询,那么打印出的sql语句中and后面会有client1_id=? and 1=1。
解释下hibernate打印出的sql语句,复合查询使用Example时,hibernate打印出的sql语句where部分其实分为两个部分,第一个部分是针对主表的查询条件,第二部分是针对关联表的查询条件。
如果没有查询条件,那么打印出的sql语句where部分为:
where 1=1 and 1= 1
如果是主表的非主键查询条件,那么打印出的sql语句where部分为:
where 主表条件 and 1=1
如果是主表的主键查询条件,那么打印出的sql语句where部分为:
where this_.id=? and 1=1 and 1=1
[注] this_.id=? and 1=1属于查询的第一部分,主表查询条件。主键查询需要使用criteria.add(Restrictions.idEq(id))。
如果是关联表的查询条件,那么打印出的sql语句where部分为:
where 1=1 and 关联表条件
如果是按照关联表的主键查询,那么打印出的sql语句where部分为:
where 1=1 and 关联表.id = ? and 1=1
[注] 关联表.id = ? and 1=1属于查询的第二部分,关联表查询条件。主键查询需要使用criteria.add(Restrictions.idEq(id))。
总结:
Hiberante在使用QBE查询时,如果是对主键查询,是不起作用的,即使主键设置了值。
在这种情况下,需要对主键查询时,可以使用criteria.add(Restrictions.idEq(id))来实现。