ORM和DAO - 设计问题

4

我目前正在参与的项目中,有这样的讨论,我想问问其他人对此的看法。

DAO模式是什么(根据维基百科):“在计算机软件中,数据访问对象(DAO)是一种对象,它为某种类型的数据库或持久性机制提供抽象接口,提供某些特定操作而不暴露数据库的详细信息。”

但是,使用ORM,这显然是ORM(例如Hibernate)的工作。它确切地为几乎任何类型的数据库提供了抽象接口。

回顾一下最近的几个项目,我们来看看DAO层。第一步始终是具有save(),findById(),findAll()方法的通用Hibernate DAO。对我来说,这只是代理Hibernate会话方法。

更进一步,我看到像这里建议的这样的接口:Hibernate中的通用DAO模式,这完全将DAO紧密地绑定到Hibernate的持久化方式(merge,criteria query)。该DAO不能与Hibernate以外的其他持久性机制一起使用。

因此,最终的想法是一个问题:对于这样的常见DAO设计,DAO模式带来了什么新东西?如果我想切换数据库引擎,我会在Hibernate级别上进行切换。那么,在ORM应用程序中使用DAO模式目前真的有任何好处吗?

让我们收集一些经验:

  1. 您有多少次看到DAO类层次结构与Hibernate(或其他ORM)紧密绑定,并且您对此有何看法?
  2. 您有多少个项目更改了持久性机制,以便通过DAO层获得了好处(即,您需要实现其他DAO层,因为通过切换db方言无法在ORM级别完成您的工作)?
  3. 您有多少个项目仅开发了大型DAO结构(每个域对象都有接口+类),并且从未真正使用过它们(即,您从未更改过基础DAO层次结构的实现)?
  4. 您认为没有DAO层的应用程序,只使用ORM会话提供的抽象是怎样的?

请分享您的经验。

1个回答

2

在我看来,使用ORM时,DAO模式并不是真正意义上的能够切换数据库引擎,而是:

  • 分离职责:业务逻辑层放在服务层,持久化操作放在DAO层
  • 可以通过mock DAO层来测试服务层
  • 因为持久化逻辑不被埋在业务逻辑中,所以可以对其进行测试

通常情况下,我更倾向于按功能用例集合建立DAO对象,而不是每个领域对象都建立一个DAO对象。确实,我发现在足够复杂的应用程序中,大多数查询都与特定的领域对象没有关联,而是与一个或多个用例相关联。但各人有各人的想法,在某些情况下结合这两种方法也很有用。

所以,回答你具体的问题:

  1. 几乎总是如此。使用Hibernate或JPA的DAO并不同于使用纯JDBC的DAO,大多数情况下是这样的。
  2. 从来没有。通常情况下,选择数据库是在项目启动之前做出的,且不会更改。
  3. 我倾向于在需要的时候才开发DAO,并不是因为存在领域对象就建立DAO。但是,拥有“通用DAO”基类有时会很方便。
  4. 我认为它们更难测试,通常结构不够明确,最终会一遍又一遍地重新实现相同的查询/加载,因为这些内容没有被隔离在可重复使用的DAO中。

谢谢回复。那么,我有另外几个问题:
  1. 你不能在服务层上模拟和测试直接使用默认实现中的Session抽象的服务吗?
  2. “DAO per usecase”是什么意思?这对我来说很新奇,因为我也在服务层上使用这种模式。
我知道这种方法中的另一个问题是要在某个地方收集访问数据的方法 - 复杂、可重复的查询。这可能默认在DAO层上完成,但通常会在服务层上重复执行,这些服务层只是这些DAO的代理(从我看不出太多好处)。
- Lukasz Frankowski
  1. 不行,因为会话方法过于粗粒度,不够具体。与其使用session.createQuery(String)接着query.setMaxResults()再接着query.list(),还不如模拟(和验证)dao.findFoosByField(String)更容易。
  2. 例如,我可能会有一个单独的DAO用于授权管理,它将处理用户、角色、配置文件的持久化,而不是一个DAO用于用户,另一个DAO用于角色,还有一个DAO用于配置文件。
- JB Nizet
好的,我明白了。在测试时,我更喜欢使用数据库填充而不是模拟,因此模拟DAO并没有真正帮助我。另一个与DAO相关的问题是限制/排序的问题。结果需要许多具有这些参数的方法,并且所有这些都已经通过非常方便的接口暴露在下一层。我真的很接近转向其他解决方案。 - Lukasz Frankowski
如果你没有真正进行单元测试,那么你的测试运行时间会比必要的时间长得多。模拟有助于测试业务逻辑,而无需维护数据集,使测试运行非常快,并且真正有助于测试边缘情况。 - JB Nizet
1
我了解这种方法,但是我很难相信它。我的应用程序通常的做法是从数据库中获取数据,处理它们,然后再将一些东西放回到数据库中。对我来说,这更接近真实情况,在数据库上测试它(顺便测试与持久性相关的事物,如关系等)。抱歉我不遵从传统,我最近手头有两个中等规模的项目,使用完全不同的方法编写,我在那里看到,经典应用程序的代码量增加了100-150%(和所需的工作时间),完全没有任何理由 - 这让我思考;) - Lukasz Frankowski
更多的代码并不一定意味着需要更多的工作时间,例如可以使用一些代码生成器。 - Pau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接