首页 新闻 会员 周边

探讨NHibernate的动态查询,走投无路了。

0
[已解决问题] 解决于 2010-11-09 15:32

需求:有一个针对泛型的数据访问接口,基本功能是:findSingle,findByCondiction,save,delete,add

理由:隔离数据访问方式于业务层。

可以看出业务层对实现一无所知,意味着数据访问层要提供的接口可以足够满足所有数据访问操作,而其实这里关键是如何做到findByCondiction,我发现NH,只有HQL是以string形式向外暴露,也只有HQL可以通过定制一个对外输入参数为string 的findByCondiction(string hql)来解决需求问题,而这样做有点拼接SQL味道,尽管HQL不是SQL,但这种方式也存在注入问题,所以我不想用。而对于Criteria,无法做到不暴露NH情况下组织查询条件,虽然它的功能很面向对象,最后的SQL原生做法就不提了和HQL方式差不多。而看回HN3的LINQ扩展,又觉得很复杂。难道要我直接在业务层暴露NH?很郁闷,我很想用Criteria动态查询。。

bugfly的主页 bugfly | 初学一级 | 园豆:10
提问于:2010-10-29 10:33
< >
分享
最佳答案
0

1) Hql 并没有注入问题, 你可以使用参数的。如from Entity a where a.Id=:id 

2) 考虑到你的接口 findByCondiction 这个方法,我觉得是建模问题,总是想用一个方法解决所有查询问题,这个是不现实的。一个大型的系统,查询非常多样,不可能就一个findByCondiction就可以解决所有问题,除非你实现了和Criteria一样整套的查询方法。 我建议是查询由子类实现,如订单,就FindByCreateTime, FindByCustomer,如果是组合查询,就新创建一个类,可以叫做OrderQuery, 有属性如CreateTime,State,Customers等,又或者用NH提供的FindExample(好像是这个名字)。

沉默的糕点 | 小虾三级 |园豆:1786 | 2010-10-29 10:55
from Entity a where a.Id=:id 这种方式,在暴露NH的情况下当然可以配置参数。但我的前提是业务层对NH一无所知,不可能有机会使用NH的接口如SetString("id",xxx)这种。所以只能直接拼接,这也是所谓的注入问题。 很认真告诉你,完全可以一个findByCondiction实现所有条件查询,Linq to SQL对于扩展表达式树就可以实现,而且也不是一两个项目用过了。你所说的用子类来扩展查询接口,是一种不好做法,UI变数据访问相应可能都会变,你不觉得这是问题?如果是这样还不如不分层,我是坚决反对这种方式来满足前端需求。面对这种需求我们应该修改临界client端的接口来满足变化,而不是数据访问层。
bugfly | 园豆:10 (初学一级) | 2010-10-29 11:36
@桀骜的灵魂:我说得不是很清楚。一般我会用IDAO<T>来做数据访问层,其中T是Entity或者直接叫做BO好了。里面只有Save,Delete等有限几个方法,然后再通过继承IDAO得出IOrderDao,然后在IOrderDao提供FindByCreateTime等与Order有关的查询。有了IOrderDao之后,再扩展出OrderDao真正的实现类(我一般会有个单独的项目,如OrderDaoNHImple)。在Web下,我会用IoC,把OrderDao和IOrderDao绑定,而在整个web中,我只使用IOrderDao这个接口。这个应该是NH最基本的用法。当然如果你用ActiveRecord方式就是另外的做法。
沉默的糕点 | 园豆:1786 (小虾三级) | 2010-10-29 17:09
这个,IOrderDao这种做法,我也用过,也是很多人的做法,你细想一下,其实IOrderDao是一种直接和需求关联的接口,和需求关联本来没什么,但可惜它是基础层的东西,修改它就意味着有连锁反映,由基础层一路波动到UI层,层数越多就越剧烈。模拟一个场景,UI界面要增加一个字段的搜索,和一个日期的范围搜索,按这种做法,搜索修改IOrderDao接口,然后在修改OrderDao,简化层次,再修改一个Service接口和实现。这种波动难道是你想得到的?说回来,我没强调用AR方式,但我坚信基础层应该一个以不变应万变的数据访问接口,而需求的变化,只应该修改Service层,或者是门面层才符合分层的初衷,至于你提到的方式确实没AR好用,所谓的分工,越分越难维护。
bugfly | 园豆:10 (初学一级) | 2010-11-01 11:44
因为IOrderDAO会提供IList<Order> SearchByExample(Order order)的方法,也就是最低限度有一定的扩展。所以增加一个字段的查询,只会在调用方修改而不会有连动的修改。而我认为在最好的办法是调用方使用Linq进行查询。但是Linq过于灵活,如果有复杂查询,一般是很少修改的,我会在DAO提供的方法。因为DB随着应用,表的数据量不断变化,索引,表分区,cache也会改变,那么HQL也好,SQL也会变化,而只修改DAO层会更好维护,更容易更新和测试。Service层我很少使用,因为做Web的多,只有做分布式的应用(如客户端是Winform、PDA)时候我才会使用Service层,而且在这些Client端都不会用NH Mapping的对象,而是用DTO,因为比较安全,我的NH的对象通常都是BO。所以Servce和UI之间的交互用DTO。Web我用MVC模式,而匿名对象天生就是很好的DTO。
沉默的糕点 | 园豆:1786 (小虾三级) | 2010-11-02 09:44
同意你的SearchByExample观点和FindByCondiction目的是一样的。以我的经验来看匿名对象是很难维护的,项目越大弊端越明显,当然可能是我的用法不对,所以我好奇你用MVC框架面对匿名对象,按你的说法是DTO吧,VO也罢,这样匿名传递,难道前台是手动人脑记忆后台匿名对象的字段再集合JS去动态解释JSON对象?这样后台省了一大笔静态对象的开销,不过前台维护噩梦正在开始,而解决这些问题我一般是用对应的ViewModel去绑定对应Page的。
bugfly | 园豆:10 (初学一级) | 2010-11-04 15:42
在MVC中,为加快响应,页面第一次的时候加载相关的信息,那么就会用到BO的,即Server端输出页面的时候,就直接输出需要的数据,如View<Entity>,<%=Entity.Id;%>。但是Ajax就会用到匿名对象,因为可以加快响应速度,另个一个原因是双向引用会引发异常,所以BO不会作为返回值的。前台的确很难受,所以我做了一个jquery plugin,用于把返回值banding到Html上,并且能够把数据从HTML中收集回来,形成JSON对象。
沉默的糕点 | 园豆:1786 (小虾三级) | 2010-11-04 23:39
听不懂你这个plugin,我理解你的话就是说反了。一个匿名对象,从后台传到前台,你的plugin不是应该从先理解匿名对象为JSON对象,从脚本解释开始得到数据然后再绑定到HTML上?怎么可能直接从后台返回的JSON绑定到HTML?不用解释数据这么神奇?
bugfly | 园豆:10 (初学一级) | 2010-11-05 10:07
页面直接自动化绑定后台匿名对象,实在太神奇了,至今我也无法理解,如果真如你所说,开发效率将会极大地提高。
bugfly | 园豆:10 (初学一级) | 2010-11-05 10:08
sorry,晚上回帖质量就是差,我自己也看到不懂。 Ajax Request 一个Action,从这个Action 返回一个匿名对象,那么这个对象会自动变为JSON,然后通过这个Plugin banding到HTML上面。 在页面输入输出之后,我会再通过这个plugin 收集数据,组成一个json对象,然后再post 这个json对象到Server。 下面是我写Plugin,支持模板,switch template的功能,可以参考一下,不过不是什么高难度东西,http://code.google.com/p/ornamentframework/downloads/list
沉默的糕点 | 园豆:1786 (小虾三级) | 2010-11-05 10:28
好的,我会研究一下,不过我环视十分好奇,前台的匿名JSON对象,后台如何解释?后台可是静态语言。没有类型如何解释得了?
bugfly | 园豆:10 (初学一级) | 2010-11-05 16:54
后台我没有更多的办法,写了个Filter,返回一个Dictionary <string,Object>的类,中间可以嵌套多个Dictionary<string,obejct> ,然后提供ToString,ToInt,ToXXX的方法。这样就不需要一个实体类。
沉默的糕点 | 园豆:1786 (小虾三级) | 2010-11-06 12:41
其他回答(2)
0

NH不太清楚,不过 ibatis 中可以通过配置xml 文件实现 动态查询 

地址:http://www.mybatis.org/dotnet.html

<select id="Server_Total" resultClass="long">
select *
from A
<dynamic prepend="where">
<isNotEmpty prepend="and" property="IpAddress">
ip_address like #IpAddress#
</isNotEmpty>
<isNotEmpty prepend="and" property="Name">
name like #Name#
</isNotEmpty>
</dynamic>
</select>

 

类似于这样

wgz | 园豆:1254 (小虾三级) | 2010-10-29 14:20
确实是类似这些,不过NH没理由没解决方法吧?
支持(0) 反对(0) bugfly | 园豆:10 (初学一级) | 2010-10-29 14:29
0

我也在找这个问题的解决方案,没有啊?

sunlovesea | 园豆:142 (初学一级) | 2016-04-12 16:38
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册