仓储模式

本文来自官网,翻译记录学习


在许多应用程序中,业务逻辑从数据存储区(例如数据库,SharePoint列表或Web服务)访问数据。直接访问数据可能导致以下结果:

  • 重复的代码
  • 编程错误的可能性更高
  • 商业数据输入不正确
  • 难以集中化与数据相关的策略(例如缓存)
  • 无法独立于外部依赖项轻松测试业务逻辑

使用存储库模式可实现以下一个或多个目标:

您希望最大化可以通过自动化进行测试的代码量,并隔离数据层以支持单元测试。
您可以从许多位置访问数据源,并希望应用集中管理的,一致的访问规则和逻辑。
您想要实现并集中数据源的缓存策略。
您想通过将业务逻辑与数据或服务访问逻辑分开来提高代码的可维护性和可读性。
您想要使用强类型的业务实体,以便可以在编译时而不是在运行时识别问题。
您想要将行为与相关数据相关联。例如,您要计算字段或在实体中的数据元素之间强制执行复杂的关系或业务规则。
您想应用域模型来简化复杂的业务逻辑。

解决方案

使用存储库将检索数据并将其映射到实体模型的逻辑与作用在模型上的业务逻辑分开。业务逻辑应该与构成数据源层的数据类型无关。例如,数据源层可以是数据库,SharePoint列表或Web服务。

存储库在应用程序的数据源层和业务层之间进行中介。它查询数据源中的数据,将数据从数据源映射到业务实体,并将业务实体中的更改持久保存到数据源。存储库将业务逻辑与与基础数据源或Web服务的交互分开。数据层和业务层之间的分离具有三个好处:

它集中了数据逻辑或Web服务访问逻辑。
它为单元测试提供了一个替换点。
它提供了一种灵活的体系结构,可以随着应用程序整体设计的发展而进行调整。
存储库可以通过两种方式查询业务实体。它可以向客户的业务逻辑提交查询对象,也可以使用指定业务标准的方法。在后一种情况下,存储库代表客户形成查询。存储库返回满足查询的一组匹配的实体。下图显示了存储库与客户端和数据源的交互。

存储库的交互

客户端将新的或更改的实体提交给存储库以保持持久性。在更复杂的情况下,客户业务逻辑可以使用工作单元模式。此模式演示了如何封装几个相互一致的或具有相关依赖性的相关操作。封装的项目将发送到存储库以进行更新或删除操作。本指南不包含工作单元模式的示例。有关更多信息,请参见Martin Fowler网站上的工作单元。

存储库是位于不同域中的数据和操作之间的桥梁。常见的情况是从数据类型较弱的域(例如数据库或SharePoint列表)映射到对象类型为强类型的域(例如域实体模型)。一个示例是使用IDbCommand对象执行查询并返回IDataReader对象的数据库。另一个示例是SharePoint,它使用SPQuery对象返回SPListItem集合。存储库向数据源发出适当的查询,然后将结果集映射到外部公开的业务实体。存储库经常使用数据映射器在制图表达之间转换的模式。存储库删除了调用客户端对特定技术的依赖性。例如,如果客户调用目录存储库以检索某些产品数据,则只需要使用目录存储库接口即可。例如,客户端不需要知道是否通过对数据库的SQL查询或对SharePoint列表的协作应用程序标记语言(CAML)查询来检索产品信息。隔离这些类型的依赖关系可以灵活地实现各种实现。

实施细节
本节讨论SharePoint列表存储库和Web服务存储库的实施策略。

SharePoint列表存储库
下图说明了SharePoint列表存储库与SharePoint列表和业务逻辑的交互。

SharePoint列表存储库的交互

在SharePoint应用程序中使用存储库模式可以解决几个问题。

SharePoint应用程序通常将业务信息存储在SharePoint列表中。要从SharePoint列表中检索数据,需要谨慎使用SharePoint API,与列表及其字段相关的GUID知识以及CAML的实用知识。存储库集中了此逻辑。
查询或更新SharePoint列表项所需的代码量足以保证将其封装到帮助器方法中。当Web窗体,事件接收器和工作流业务逻辑都需要访问相同的列表时,可以在整个应用程序中复制访问SharePoint列表的代码。这会使应用程序容易出现错误,并且难以维护。存储库消除了这种重复。
没有存储库,应用程序很难进行单元测试,因为业务逻辑直接依赖于SharePoint列表。存储库集中了访问逻辑,并为单元测试提供了一个替换点。
在外部,存储库公开了类型严格的业务实体。在内部,它与特定于SharePoint的对象一起使用,例如SPQuery和SPListItem对象。作为本指南一部分的SharePoint指导库提供了用于映射和查询的类,这些类使构建SharePoint列表的存储库更加容易。该ListItemFieldMapper类转换强类型的业务实体和SPListItem对象基于一组的映射定义。该CAMLQueryBuilder类构建SPQuery对象基于共同的查询操作。该SPQuery对象用于查询SharePoint列表。

以下各节说明如何在SharePoint指导库中实现存储库模式。有关更多信息,请参见基于列表的存储库。

SharePoint指导库帮助程序类
下图显示了SharePoint列表存储库的主要组件。

SharePoint列表存储库的组件

列表存储库包含特定于SharePoint的查询对象和数据映射器对象。这些是ListItemFieldMapper和CAMLQueryBuilder类。数据映射器在SPListItem和应用程序定义的业务实体之间转换。查询对象在内部构造一个SPQuery对象,并使用CAML查询列表。

备注

设计SharePoint列表存储库时,请记住,列表可以包含来自多个内容类型的字段。在ListItemFieldMapper和CAMLQueryBuilder对象中实现的逻辑不会阻止检索来自多个内容类型的字段。在某些情况下,如果内容类型具有相同的父内容类型,则可以使用单个存储库在这些内容类型上投影通用视图。
但是,通常不建议创建处理不同内容类型的存储库,并从同一存储库返回不同的业务实体。在这种情况下,请为每种内容类型创建一个存储库,因为这些内容类型在逻辑上表示不同的实体。

实施变体
创建SharePoint列表存储库时,应考虑存储库如何定位要访问的列表。列表通常位于站点中,并且可以通过其统一资源标识符(URI)或GUID对其进行访问。存储库需要其中之一,但是如果将此存储库与服务位置结合使用,则将信息传递到存储库可能会很困难。有关更多信息,请参见服务定位器模式。

存储库可以通过三种方式访问列表:

列表可以位于中心。在这种情况下,存储库与固定位置的列表相关联。所有站点都从该中心位置检索数据。Partner Portal应用程序中的PartnerPromotionsRepository类是使用诸如list之类的存储库的示例。
可以相对于当前站点上下文访问列表。在这种情况下,存储库与位置相对于当前站点的列表相关联。合作伙伴门户网站应用程序中的IncidentManagementRepository类是此类存储库的示例。
可以根据消费者提供的上下文来访问列表。在这种情况下,只有存储库的使用者知道存储库应访问的列表。合作伙伴门户网站应用程序中没有此示例。但是,您可以扩展Training Management应用程序以支持此用例。您可以实现一个存储库,该存储库可以在本地安装中访问部门的培训课程列表,还可以访问另一个部门站点上的相关培训课程。在这种情况下,使用者指示存储库以特定列表为目标。
以下各节描述有关如何将存储库与列表关联的更多详细信息。

从固定位置集中访问的列表
在这种情况下,列表位于固定位置,并且所有站点都从该中心点访问列表。无法根据当前上下文确定其位置。尽管可以对列表的位置进行硬编码,但是不建议这样做,因为站点的拓扑可以更改。通常最好将列表的位置设置为配置设置。在这种情况下,定义列表的位置是一项管理任务。设置站点拓扑时将建立位置。

例如,合作伙伴门户应用程序通过将所有合作伙伴放在一个网站集上来集中管理所有发布的促销。合作伙伴可以在其协作主页上看到其特定的促销活动。每个合作伙伴协作网站都托管在其自己的网站集中。这将建立安全边界,并将打算供一个伙伴使用的数据与打算供另一伙伴使用的数据隔离。因为列表和列表使用者之间的关系基于操作拓扑,所以列表位置是用配置数据定义的。

以下是具有固定位置的列表的特征:

在Web应用程序范围内,通常只有该列表的一个实例。
列表的位置是在设计站点拓扑或安装站点时确定的。
列表位置应从所有使用者共享的配置数据中检索。此数据通常在Web应用程序级别或Web服务器场级别。
下图显示了在中心位置访问列表的组件之间的信息流。

将存储库与中央位置的列表相关联

服务定位器构造一个存储库对象,然后读取该存储库的配置信息。存储库基于此数据访问列表。由于存储库依赖于配置数据,因此可以独立于应用程序上下文来构建存储库。它不需要列表使用者的任何其他信息。

这种方法容易受到运行时异常的影响,因为它依赖于配置数据,配置数据可能是错误,丢失或损坏的。确保提供足够的诊断信息,以将任何配置错误通知IT管理员。没有足够的日志信息,很难解决由配置错误引起的问题。

相对于当前上下文具有固定位置的列表
在这种情况下,存储库与相对于当前上下文位置固定的列表相关联。例如,在“培训管理”应用程序中,注册和课程列表位于站点内相同的相对位置。但是,SharePoint服务器场中可以有多个Training Management网站。在这种情况下,列表存储库是从当前上下文加载的。

以下是具有相对于上下文的位置的列表的特征:

该列表具有相对于站点(SPWeb对象)的固定位置。
该位置独立于站点拓扑。
列表位置基于当前的SharePoint上下文。
下图显示了使用相对于上下文的位置访问列表的信息的组成和流。

将存储库与位置相对于上下文的列表相关联

SharePoint通常具有同一Web应用程序的许多实例。在这种情况下,资源库从SharePoint上下文(SPContext.Current.Web对象)获取当前站点,并从该上下文加载列表信息。由于此关系相对于当前站点是固定的,因此存储库不需要其他信息。存储库实例可以由服务定位器直接构建。

列出消费者提供其上下文的人
在这种情况下,存储库与特定的内容类型相关联,并且可以访问具有此内容类型的SPListItem的任何列表。使用者必须向存储库提供上下文。例如,使用者可以提供包含列表或列表的GUID的SPWeb对象。尽管通常最好的做法是将技术特定的依赖性(例如对SQL Server的依赖)排除在存储库接口之外,但是在构建存储库时提供上下文是一种公认的,广泛使用的做法。

这种情况发生在具有动态拓扑的站点或提供配置信息的用户建立关系的站点上。如果在运行时添加或删除包含存储库访问的列表的站点,则通常必须提供上下文。一个示例是,如果您使用“财务”培训站点来查看课程,但是还希望在“人力资源”培训站点上查看这些课程。

要提供此功能,您可以构建一个通用的Web部件来查看其他部门培训站点中的课程。您可以将此Web部件添加到Finance培训站点,并对其进行配置以查看相关的人力资源部门课程。财务站点上的Web部件使用的存储库在构建Web部件时会接收人力资源课程列表的位置作为上下文信息。

这种存储库的一个挑战是将其与SharePoint Guidance库服务定位器结合使用。该ActivatingServiceLocator类只能使用参数构造函数的库。无法通过构造函数将上下文信息(在这种情况下为列表的位置)传递到存储库中。解决此问题的一种方法是在每个方法调用中传递列表的位置,但这会将对列表URL的依赖项插入接口定义中。培训管理应用程序使用此方法。

将列表的位置传递到存储库的更好但更复杂的方法是使用工厂。工厂包括创建存储库的方法。使用者将列表的位置传递给方法。然后,使用者使用ActivatingServiceLocator来访问工厂并使用它来创建存储库。使用这种方法,消费者将清单的位置提供给工厂,然后由工厂创建存储库。工厂通过存储库构造函数传递上下文。此技术称为构造函数注入。

以下是其上下文由使用者提供的列表的特征:

  • 使用者可以确定存储库应访问的列表。
  • 列表的位置通常在运行时确定。
  • 该列表位置是从当前业务环境派生的。
  • 下图显示了访问由使用者提供上下文的列表所涉及的组件和信息流。

将存储库与清单的上下文由使用者提供

使用者为存储库构造上下文。使用者从服务定位器检索存储库工厂的实例。然后,使用者使用存储库工厂来构建存储库。使用者提供列表的上下文。存储库使用此信息来找到列表。因为存储库与配置数据和上下文都没有关联,所以它适用于许多情况。但是,由于使用者提供了上下文,因此它增加了使用者代码与存储库之间的耦合。

Web服务存储库
通用的数据后备存储是由业务线(LOB)应用程序公开的业务服务。通常,这些业务服务处于比数据库或SharePoint列表的标准创建/读取/更新/删除(CRUD)语义更高的抽象级别。但是,从客户端的角度来看,它们通常等效于数据源。与SharePoint列表一样,访问Web服务可能很复杂并且容易出错。存储库集中了服务的访问逻辑,并提供了单元测试的替代点。请注意,调用服务通常很昂贵,而且要从存储库内实现的缓存策略中受益。

下图显示了使用缓存的服务后端存储库。

将存储库与Web服务一起使用

在这种情况下,存储库中的查询逻辑首先检查以查看查询的项目是否在高速缓存中。如果不是,则存储库访问Web服务以检索信息。尽管可以直接访问服务,但是也可以通过SharePoint业务数据目录(BDC)访问它们。BDC可以聚合包括Web服务在内的多个数据源,并通过统一的通用接口公开它们。BDC允许您使用标准的Web部件来显示和修改数据。有关更多信息,请参见使用业务数据目录(BDC)消耗Web服务。

您可能需要比BDC支持的更复杂的安全性选项。在这种情况下,您可以使用Windows Communication Foundation(WCF)。这需要您自己的代码和配置数据来管理服务信息和安全上下文。有关更多信息,请参见集成业务线系统。

储存库示例
有关列表存储库模式的示例,请参见开发方法主题。此外,合作伙伴门户网站应用程序包括以下列表存储库,可以用作起点:

合作伙伴促销存储库位于PartnerPortal \ Contoso.PartnerPortal.Promotions目录的PartnerPromotionRepository.cs文件中。PartnerPortal \ Contoso.PartnerPortal.Promotions.Tests目录的PartnerPromotionsPresenterFixture.cs文件中还有一个用于单元测试的模拟实现。
业务事件类型配置存储库位于Microsoft.Practices.SPG2 \ Microsoft.Practices.SPG.SubSiteCreation \ BusinessEventTypeConfiguration目录的BusinessEventTypeConfigurationRepository.cs文件中。Microsoft.Practices.SPG2 \ Microsoft.Practices.SPG.SubSiteCreation.Tests目录的ResolveSiteTemplateFixture.cs文件中还有一个用于单元测试的模拟实现。
子站点创建请求存储库位于目录Microsoft.Practices.SPG2 \ Microsoft.Practices.SPG.SubSiteCreation \ SubSiteCreationRequests的SubSiteCreationRequestsRepository.cs文件中。
有关使用Web服务的数据存储库模式的示例,请参见参考实现的以下区域:

事件管理存储库位于PartnerPortal \ Contoso.LOB.Services.Client \ Repository目录的IncidentManagementRepository.cs文件中。
定价存储库位于PartnerPortal \ Contoso.LOB.Services.Client \ Repositories目录的PricingRepository.cs文件中。
缓存的BDC产品目录存储库位于目录PartnerPortal \ Contoso.LOB.Services.Client \ Repositories的CachedBdcProductCatalogRepository.cs文件中。在目录PartnerPortal \ Contoso.PartnerPortal.ProductCatalog.Tests的ProductDetailsPresenterFixture.cs文件中,还有一个用于单元测试的模拟实现。
Partner Portal应用程序还包含其他两个存储库:

全文搜索IncidentTask存储库使用SharePoint搜索作为其数据源。该存储库位于目录PartnerPortal \ Contoso.PartnerPortal.Collaboration.Incident \ Repositories的FullTextSearchIncidentTaskRepository.cs文件中。
合作伙伴网站目录使用网站目录列表提供合作伙伴网站集URL,并使用用户配置文件提供PartnerID。该存储库在目录PartnerPortal \ Contoso.PartnerPortal.PartnerDirectory的PartnerSiteDirectory.cs文件中实现。
有关“存储库”模式,“工作单位”模式和“数据映射器”模式的更多信息,请参阅Martin Fowler网站上的“存储库”。

注意事项
存储库模式提高了代码中的抽象级别。对于不熟悉该模式的开发人员,这可能会使代码更难以理解。尽管实施该模式可以减少冗余代码的数量,但通常会增加必须维护的类的数量。

存储库模式有助于隔离服务和列表访问代码。通过隔离,可以更轻松地将它们视为独立服务,并在单元测试中将其替换为模拟对象。通常,很难对存储库本身进行单元测试,因此通常为它们编写集成测试会更好。

在多线程环境中缓存数据时,除了要缓存的对象外,还应考虑同步对缓存的访问。通常,常见的缓存(例如ASP.NET缓存)已经是线程安全的,但是您还必须确保对象本身可以在多线程环境中运行。

如果要在负载较重的系统中缓存数据,则性能可能会成为问题。考虑同步对数据源的访问。这样可以确保仅将对数据的单个请求发布到列表或后端服务。所有其他客户端都依赖于检索到的数据。有关更多信息,请参见汇总列表和站点信息的技术。

相关模式
以下两种模式通常与存储库模式结合使用:

数据映射器。此模式描述了如何将数据映射到不同的模式。它通常用于在数据存储和域模型之间进行映射。
工作单位。此模式跟踪影响数据库的业务交易过程中发生的所有事情。在事务结束时,它确定如何更新数据库以符合更改。

原文出处:MSDN
原文链接: https://docs.microsoft.com/zh-cn/previous-versions/msp-n-p/ff649690(v=pandp.10)?redirectedfrom=MSDN
文章标题:仓储模式
文章链接:https://onebyone.icu/archives/1250
作者昵称:OneByOneDotNet
作者链接:https://onebyone.icu/user/1

本网站(网站地址)刊载的所有内容,包括文字、图片、音频、视频、软件、程序、以及网页版式设计等均在网上搜集。 访问者可将本网站提供的内容或服务用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯本网站及相关权利人的合法权利。除此以外,将本网站任何内容或服务用于其他用途时,须征得本网站及相关权利人的书面许可,并支付报酬。 本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站,予以删除。 转载请注明出处

发表评论

邮箱地址不会被公开。 必填项已用*标注

WeChat
WeChat
QQ
QQ
返回顶部