DAO和Repository模式有什么区别?

Thu*_*ein 397 domain-driven-design hibernate data-access-layer repository-pattern ejb-3.0

数据访问对象(DAO)和存储库模式之间有什么区别?我正在开发一个使用Enterprise Java Beans(EJB3),Hibernate ORM作为基础架构,域驱动设计(DDD)和测试驱动开发(TDD)作为设计技术的应用程序.

que*_*rin 435

DAO是数据持久性的抽象.存储库是对象集合的抽象.

DAO将被认为更接近数据库,通常以表格为中心.存储库将被视为更接近域,仅处理聚合根.可以使用DAO实现存储库,但是你不会做相反的事情.

此外,存储库通常是较窄的接口.它应该是简单对象的集合,有DAO,Repository,DAO.类似的方法Repository适用于DAO,但不适用于存储库 - 使用存储库时,通常会通过单独的UnitOfWork跟踪对实体的更改.

看到实际上称为存储库的实现更像是一个DAO似乎很常见,因此我认为它们之间存在一些混淆.

  • 我在.NET世界中特别注意到术语"存储库"用于指代本质上是DAO的东西; "DAO"更像是一个Java术语. (28认同)
  • 好吧,你不希望你的DAO类实际上实现你的`IRepository`接口.您希望您的存储库在其实现中使用DAO.请记住,DAO将是每个表对象,而存储库几乎总是必须使用多个DAO来构建单个实体.如果您发现情况并非如此,那么您的存储库和实体只需要访问单个表,那么您很可能构建一个贫血域. (22认同)
  • @Stef我不同意.DAO通过其定义(a*data*访问对象)返回*data*.根据其定义,存储库返回域对象.应该有理由认为存储库会使用DAO而不是相反,因为在OOP中我们用一个或多个数据对象组成域对象,而不是相反. (18认同)
  • @Thurein DAO-s不是每个表,模式只是抽象对数据的访问 - 你可以实现你喜欢的(每个表,或每个组或模型).建议的方法是始终根据您的域模型对DAO进行整形,而不是将底层持久性考虑在内,因为这样可以更容易/更清晰地使用它,并为您提供更灵活的持久性(例如,想象您需要)一个DAO,它将您的数据存储在XML文件中,或者从消息队列而不是从数据库中获取...). (14认同)
  • 为什么存储库是"只读"概念,而DAO是"读写"? (5认同)
  • @MihaiDanila,对不起我刚刚看到你的评论.是的,DAO是一个允许您访问数据的对象,与Repository相同,它抽象数据库连接和通信并返回域对象而不是ResultSet或其他DB特定.从概念上讲,你甚至可以认为它们是相同的.但是如果你看看它们是如何被使用的,你会注意到它只使用了一个,或者DAO连接到了Repository.它们的使用方式如我在下面的答案中所述.存储库处理一种类型的对象(通常来自一个表),而DAO更松散并且可以处理相关模型. (3认同)
  • Eric Evans(领域驱动设计)描述存储库应该模拟对象集合,但 Vaughn Vernon(实现领域驱动设计)对基于集合的存储库和基于持久性的存储库进行了区分。因此,如果您的存储库使用直接表示数据库的对象,并且您没有将存储库用作内存中集合(只是使用它来抽象数据库),那么您所做的几乎与传统 DAO 的操作相同。 (3认同)
  • @drizin 在这里提出了一个非常好的观点,例如在 Spring Data 的情况下,存储库充当 DAO,它是一个“基于持久性”的存储库。 (3认同)
  • 设计模式既有害又有用。 (2认同)
  • 事实并非如此,并且 Repository 在最新框架中的使用方式(例如,参见 Spring 或 spring-data)证实了 Repository 实际上是两者中“较笨”的一个。存储库(与 DAO 相同)是一个抽象,用于隐藏数据检索/保存的位置和方式(注意保存/更新是存储库职责的一部分)。DAO 基本上是相同的,尽管你可以将其视为一个稍微更广泛的概念。如果您想同时使用两者,DAO 可以使用一个存储库或一组存储库来访问您的数据。请注意,有些称为 DAO-s 提供者。(例如 UserInformationProvider 而不是 UserInformationDao)。 (2认同)
  • 您提到了“ Add(Entity)”作为存储库模式的示例。但是,存储库是抽象所有持久性的,因此它在域内部,并且仅适用于域/业务对象,不适用于实体。存储库不应公开表表示形式(实体) (2认同)
  • 和丹尼斯有同样的问题。为什么我们不应该在存储库中拥有删除/更新方法?许多其他指南不断显示相反的情况。为什么有这么多歧义? (2认同)

Ste*_*tef 112

好的,我想我可以更好地解释我在评论中提出的内容:).所以,基本上,你可以看到两者相同,尽管DAO比Repository更灵活.如果要同时使用两者,则可以在DAO-s中使用存储库.我将在下面解释它们:

仓库:

它是特定类型对象的存储库 - 它允许您搜索特定类型的对象以及存储它们.通常它只能处理一种类型的对象.例如AppleRepository,允许你做AppleRepository.findAll(criteria)AppleRepository.save(juicyApple).请注意,存储库使用的是域模型术语(不是数据库术语 - 与数据在任何地方的持久性无关).

存储库很可能将所有数据存储在同一个表中,而模式不需要这样.事实上,它只处理一种类型的数据,使其逻辑上连接到一个主表(如果用于数据库持久性).

DAO - 数据访问对象(换句话说 - 用于访问数据的对象)

DAO是一个为您定位数据的类(它主要是一个查找程序,但它通常用于存储数据).该模式不会限制您存储相同类型的数据,因此您可以轻松地使用DAO来定位/存储相关对象.

例如,您可以轻松地使UserDao公开类似的方法

Collection<Permission> findPermissionsForUser(String userId)
User findUser(String userId)
Collection<User> findUsersForPermission(Permission permission)
Run Code Online (Sandbox Code Playgroud)

所有这些都与用户(和安全性)相关,并且可以在相同的DAO下指定.存储库不是这种情况.

最后

请注意,这两种模式的确意味着相同(它们存储数据并抽象对它的访问,它们都表示更接近域模型,几乎不包含任何数据库引用),但它们的使用方式可能略有不同,DAO正在更灵活/更通用,而Repository对某种类型更具体和限制.

  • 供参考http://thinkinginobjects.com/2012/08/26/dont-use-dao-use-repository/ (4认同)
  • Spring Data的优点在于您实际上不必编写查询,您只需创建一个接口(就像您的示例中的TodoRepository,它具有`findById`方法).你几乎完成了.然后Spring Data所做的就是找到你创建的所有这些接口,它们扩展了Repository接口并为你创建了类.你永远不会看到这些类,你将无法创建新的实例,但你不需要,因为你可以只是自动装配接口,让Spring找到该存储库对象. (2认同)
  • "聚合根"是通常连接到存储库模式的术语.我不知道你如何使用你的存储库定义. (2认同)

Naz*_*rza 78

DAO和Repository模式是实现数据访问层(DAL)的方式.所以,让我们先从DAL开始吧.

访问数据库的面向对象的应用程序必须具有一些处理数据库访问的逻辑.为了保持代码清洁和模块化,建议将数据库访问逻辑隔离到单独的模块中.在分层架构中,此模块是DAL.

到目前为止,我们还没有谈到任何特定的实现:只是将数据库访问逻辑放在一个单独的模块中的一般原则.

现在,我们如何实现这一原则?好吧,有人知道实现这个的方法,特别是像Hibernate这样的框架,就是DAO模式.

DAO模式是一种生成DAL的方式,通常,每个域实体都有自己的DAO.例如,UserUserDao,AppointmentAppointmentDao等DAO与Hibernate的一个例子:http://gochev.blogspot.ca/2009/08/hibernate-generic-dao.html.

那么什么是Repository模式?像DAO一样,Repository模式也是实现DAL的一种方式.Repository模式的要点是,从客户端/用户的角度来看,它应该看起来或表现为集合.表现得像集合的意思并不是它必须像实例一样被实例化Collection collection = new SomeCollection().相反,它意味着它应该支持诸如add,remove,contains等操作.这是Repository模式的本质.

实际上,例如在使用Hibernate的情况下,Repository模式是用DAO实现的.这是DAL的一个实例可以同时是DAO模式和Repository模式的实例.

存储库模式不一定是建立在DAO之上的东西(正如某些人所暗示的那样).如果DAO设计有支持上述操作的接口,则它是Repository模式的实例.想一想,如果DAO已经提供了类似集合的操作集,那么在它上面需要一个额外的层是什么?

  • “如果DAO已经提供了类似集合的一组操作,那么在它之上需要一个额外的层是什么呢?” 假设您正在为一家宠物店建模,并且有一个表“ PetType”,其中包含不同动物及其属性(名称:“猫”,类型:“哺乳动物”等),由您所养宠物的表“宠物”引用在商店中(名称:“ Katniss”,品种:“ Calico”等)。如果要添加数据库中尚未存在的类型的动物,则可以使用存储库以一种方法将两个单独的DAO调用分组(一个用于创建PetType,另一个用于Pet),避免在DAO中耦合 (2认同)

小智 64

坦率地说,这看起来像是语义上的区别,而不是技术上的区别.短语数据访问对象根本不涉及"数据库".而且,虽然您可以将其设计为以数据库为中心,但我认为大多数人会认为这样做是一个设计漏洞.

DAO的目的是隐藏数据访问机制的实现细节.存储库模式有何不同?据我所知,事实并非如此.说一个存储库 DAO 不同,因为你正在处理/返回一个对象的集合是不对的; DAO还可以返回对象集合.

我读到的关于存储库模式的所有内容似乎都依赖于这种区别:糟糕的DAO设计与良好的DAO设计(又名存储库设计模式).

  • 是的,完全同意,他们基本上是一样的.DAO听起来与DB有关,但事实并非如此.与Repository相同,它只是一个用于隐藏数据位置和方式的抽象. (4认同)
  • +1 对于此声明。坦率地说,这看起来像是语义上的区别,而不是技术上的区别。短语“数据访问对象”根本不是指“数据库”。 (2认同)
  • 比较存储库和集合时的要点不是它们处理/返回对象集合,而是存储库的行为就像它们本身是集合一样。例如,在 Java 中,这意味着存储库没有更新方法,因为当您修改集合中的对象时,它会自动更新(因为 Java 集合只存储对对象的引用)。 (2认同)

Moh*_*bed 17

存储库是更抽象的面向领域的术语,是域驱动设计的一部分,它是域设计和通用语言的一部分,DAO是数据访问技术的技术抽象,存储库仅涉及管理现有数据和工厂以创建数据.

检查这些链接:

http://warren.mayocchi.com/2006/07/27/repository-or-dao/ http://fabiomaulo.blogspot.com/2009/09/repository-or-dao-repository.html


Gk *_*mon 15

DAO允许以更简单的方式从存储中获取数据,隐藏丑陋的查询

存储库也处理数据并隐藏查询等,但是存储库处理业务/域对象

存储库将使用 DAO 从存储中获取数据并使用该数据来恢复业务对象

例如,DAO可以包含一些类似的方法 -

 public abstract class MangoDAO{
   abstract List<Mango>> getAllMangoes();
   abstract Mango getMangoByID(long mangoID);
}
Run Code Online (Sandbox Code Playgroud)

存储库可以包含类似的方法 -

   public abstract class MangoRepository{
       MangoDao mangoDao = new MangDao;

       Mango getExportQualityMango(){

       for(Mango mango:mangoDao.getAllMangoes()){
        /*Here some business logics are being applied.*/
        if(mango.isSkinFresh()&&mangoIsLarge(){
           mango.setDetails("It is an export quality mango");
            return mango;
           }
       }
    }
}
Run Code Online (Sandbox Code Playgroud)

教程帮助我轻松掌握主要概念。


pab*_*cin 6

关键的区别在于存储库处理对聚合中聚合根的访问,而DAO处理对实体的访问.因此,存储库通常会将聚合根的实际持久性委托给DAO.此外,由于聚合根必须处理其他实体的访问,因此可能需要将此访问权委托给其他DAO.


小智 5

存储库只不过是精心设计的 DAO。

ORM 以表为中心,但不是以 DAO 为中心。

无需在存储库中使用多个 DAO,因为 DAO 本身可以对 ORM 存储库/实体或任何 DAL 提供程序执行完全相同的操作,无论汽车在何处以及如何持久保存 1 个表、2 个表、n 个表、半个表、一个Web 服务、表和 Web 服务等。服务使用多个 DAO/存储库。

我自己的DAO,假设CarDao只处理Car DTO,我的意思是,只在输入中接受Car DTO,并且在输出中只返回car DTO或car DTO集合。

所以就像Repository一样,DAO实际上是一个IoC,对于业务逻辑来说,允许持久化接口不会被持久化策略或遗留问题吓倒。DAO 既封装了持久化策略,又提供了与域相关的持久化接口。对于那些不了解定义明确的 DAO 实际上是什么的人来说,存储库只是另一个词。

  • 同意@brokenthorn。他的评论中最关键的一点是“存储库是最高的抽象”,当您想要保护域代码免受底层数据库技术的影响时,这种抽象就成为必要的。ORM/适配器/数据库驱动程序概念往往会渗透到 DAO 中。如果您的应用程序支持多种数据库技术,或者您希望应用程序不被锁定到数据库,则直接从域模型使用 DAO 是不行的。 (3认同)

Rah*_*ogi 5

DAO 提供了对数据库/数据文件或任何其他持久性机制的抽象,以便可以在不知道其实现细节的情况下操作持久层。

而在 Repository 类中,可以在单个 Repository 方法中使用多个 DAO 类,以从“应用程序角度”完成操作。因此,不要在域层使用多个 DAO,而是使用存储库来完成它。存储库是一个可能包含一些应用程序逻辑的层,例如:如果数据在内存缓存中可用,则从缓存中获取数据,否则从网络中获取数据并将其存储在内存缓存中以备下次检索。