请教一个一直以来困扰我的关于DAO模式的问题!!!

首先,对于DAO模式我是非常支持,从开发实践经验来看,将业务逻辑和持久化机制分离确实带来了很大的好处。但有个问题一直没想通,也没有找到好的解决办法,在这里提出来,希望能得到高手的帮忙。

在企业应用的开发中,经常对遇到一些非常复杂的查询,尤其是需要对很多表进行关联查询。而在DAO对象中无法将这种需求封装起来,这就造成不得不在业务逻辑中包含与持久化机制相关的代码(虽然可以做到仅仅是传送一条String型的SQL语句,但毕竟这也与持久层发生了耦合,味道很坏),请问各位高人有没有什么好的办法解决这个问题,谢谢!!!!

>经常对遇到一些非常复杂的查询,尤其是需要对很多表进行关联查询
按照Evans DDD,尽量使用Critirea,也可以将这些SQl作为领域的业务规则。

谢谢banq的解答。

我也曾考虑过用Criteria这种更加面向对象的方式(纠正一下,应该Criteria是面向对象的SQL,HQL才是完全面向对象的),可惜Hibernate对Criteria的实现还不够完善,官方也推荐HQL。

另外,如果在业务逻辑中使用Criteria就得使用Session,这就还是没办法与持久层实现分离。似乎跟直接传String型的HQL语句到DAO对象的find方法没什么区别,甚至更复杂了。

至于设计为业务规则,也有一定难度,比如本身就是要做一个查询引擎,查询条件就是由用户来动态设置这种情况。

请问还有什么其它更好的办法吗?
[该贴被maybeiamtooold于2008-01-24 22:38修改过]
[该贴被maybeiamtooold于2008-01-24 22:40修改过]
[该贴被maybeiamtooold于2008-01-24 22:43修改过]

业务逻辑中怎么会出现Session?HQL语句在业务里出现也不对呀。这些东西通通应该封到DAO里头,Service里一个也不应该出现。

只要建好相应的领域模型,再复杂的多表关联查询DAO中都可以进行封装,查询出来的结果就是你按需求设计的某个领域对象或对象集合,只是这个对象中的各个属性可能分布于很多关联表中,这是一种解决方案。

Criteria比HQL更加OO,HQL才是一种SQL变种。

Evans DDD中专门有一个specification章节讨论这个问题,结合筛选,后面还谈到规格的组合设计,当然如果觉得SQL放在模型specification中不太好,也可以放入仓储中,specification需要和仓储进行交互。

这些方式其实都是说明:将复杂的SQL语句分离,变成模型对象的过滤和筛选,这样,我们就可以动态建立一些过滤器或筛选组件,对来自仓储的领域模型进行层层筛选最后变成客户端需要的结果。

具体可以参考JiveJdon3的一些复杂查询,在JiveJdon3的持久层中很难见到复杂的SQL语句,难道这个论坛不需要复杂的SQL语句?当然不是,而是我们将之分解了,很多组合筛选动作在内存中实现,然后将筛选结果cache,避免多次操作浪费性能。

>业务逻辑中使用Criteria就得使用Session,这就还是没办法与持久层实现分离
这是因为你使用了Hibernate的Criteria,可以制造自己的Criteria,我在JiveJdon3中就这样做了,不依赖持久层。

谢谢wlmouse,bonepole,banq.

虽然可以通过自建Criteria来实现和持久层的分离,但这算不算重新发明轮子呢?

Criteria是完全面向对象的 而hql则不是;
只要自己有创新和需求就不是重新发明轮子,学以至用,用可创新,创新为需!

非常好的帖子,也是一直困扰我的问题。

Criteria是一种很理想的解决方案,(当然不是指Hibernate的Criteria,即使Hibernate的Criteria将来设计的如何完美,我们也不能让持久层框架直接以它作为查询的OO封装,因为这样我们的持久层使用者,通常是业务层就必须耦合于Hiernate了,所以Criteria应该是独立设计的接口,实现当然可以来源于任何地方,包括Hibernate)。

但,问题还是,要设计一个能符合多种复杂查询的完全OO的Criteria,确实不是一件容易事情,至少Hibernate还没能很好的解决。