我自己的一生

是你的,是我的,到底是谁的?

导航

 

数据访问逻辑组件

无论你选择的数据存储是什么,应用程序或服务都要使用数据访问逻辑组件来访问数据。这些组件抽象了暗含在数据存储和数据访问技术(如。ADO.NEt)里面的语义,提供简单的程序接口为获取和执行数据的操作。

 

数据访问逻辑组件一般实现是无状态模式,从数据访问逻辑中隔离业务处理。每个数据访问逻辑组件典型的是提供创建(Create),读取(ready),刷新(Update)和删除(Delete)(CRUD)操作应用程序中的相关的指定业务实体(如,订单)。这些方法被业务处理使用。特别是查询,被用户界面用于绘制引用数据(如有效的信用卡类型列表)。

 

当应用程序包含多个数据访问逻辑组件是,有效的是,使用一般的数据访问帮助组件(helper)来管理数据库连接,执行命令,缓存参数等等。一般数据访问帮助工具组件集中了数据访问API的开发和数据连接配置,可以减少代码的重复,数据访问逻辑组件提供逻辑请求需要访问指定的业务数据。数据访问帮助组件的好的设计不会有性能的的影响,提供一个集中的地方,可以进行数据访问转换和优化。微软为DotNET提供了数据访问应用程序块(http://msdn.microsoft.com/library/en-us/dnbda/html/daab-rm.asp),当使用SQL Server数据库时,这个块可以当作一般的数据帮助工具组件用在应用程序中。

 

2.12显示了数据访问逻辑组件访问数据的用法。

 

注意图2.12中的以下几点:

 

2.12 数据访问逻辑组件

 

1.       数据访问逻辑组件暴露插入,删除,刷新和获取数据的方法。当数据量大时,包括预先规定的分页功能。

2.       可以使用数据访问帮助组件来集中链接管理和处理所有的指定的数据源的处理。

3.       如果数据源支持,用存储过程实现查询和数据操作,可以增强性能和维护性。

 

注意:所有需要访问业务数据(如,产品,订单等等)被推荐使用数据访问逻辑组件。然而,其它产品和技术使用数据库来存储自己的运行数据,不需要为自定义数据访问逻辑组件。

 

数据访问逻辑组件提供简单的访问数据库的功能(查询和数据操作),返回简单的和复杂的数据结构。对使用它们的业务组件和用户界面,隐藏了数据存储的格式语义和Invocation。在数据访问逻辑组件中实现的数据访问逻辑允许你封装所有的单元的、集中的应用程序的数据访问逻辑,确保更容易维护和扩展。

 

设计的每个数据访问逻辑组件仅处理一个数据存储。(这个意味着,这些组件不能查询和集合来自多个源的数据;这个通过业务组件处理。)

 

当使用异构事务处理时,数据访问组件将参与其中,但它们从不作为事务的根。更有效的方法有一个业务组件作为事务处理的根,这里面有一个或者多个数据访问逻辑组件用来执行数据库的刷新。

 

数据访问逻辑组件的功能

当被调用时,数据访问逻辑组件有以下方面的典型做法:

为输入和输出参数执行简单的映射和转换。这个是从数据库指定架构和存储过程签名中抽取出的业务逻辑。

访问的数据仅来源于一个数据源。这个改善了可维护性,通过移动所有的数据集合功能给业务组件,这里的数据可以按照指定的正在被执行的业务操作的行为集合。

作用于主表,也可以执行和它相关表操作。(数据访问逻辑组件不一定必须仅封装一个暗含的数据源下的对一个表的操作。)这个强调了应用程序的可维护性。

 

可选择性地,它们可以执行以下的工作:

使用一个自定义工具组件来管理和封装优化锁的架构。

使用自定义工具组件来为非事务查询结果实现数据缓存策略。

为每个大型可度量的系统实现动态的数据路由,提供对横穿多个数据库服务器的分布式数据的可度量性。

 

数据访问逻辑组件不需要做:

调用其它数据访问逻辑组件。在数据访问逻辑组件设计中避免调用另外的数据访问逻辑组件,有利于保持数据的可预测,因此,改善应用程序的可维护性。

发起异构事务。既然每个数据访问逻辑组件仅处理单个数据源,数据访问逻辑组件作为异构事务的根是没有生存的环境。然而,在一些情况下,数据访问逻辑组件可以控制调用多次刷新单个数据源的事务。

在方法调用之间维护状态。

 

数据访问逻辑组件接口设计

数据访问逻辑组件一般需要提供接口给下面的使用者:

业务组件和工作流。数据访问逻辑组件需要提供非连接业务文档的I/O,或者无状态的梯形数据(scalars in stateless),功能风格方法,如GetOrderHeader().

用户界面组件。用户交互组件可以使用数据访问逻辑组件为未连接的业务文档的I/O来展现数据在富客户端和未连接的客户端场景下,或者为流输出(如,获取一个DataReader),对于ASP.NET或者从流展现有益的客户端。如果想获取快速的优势,考虑由用户界面直接使用数据访问逻辑组件,你不需要在用户界面和数据源直接增加额外的业务逻辑。

 

数据访问逻辑组件可以使用数据访问API(如ADO.NET)直接连接数据库,或者在更复杂的应用程序中,可以选择提供额外的数据访问帮助组件,抽象访问数据库的复杂性。在另一个情况下,当使用关系数据库时,要尽量使用存储过程来执行实际数据获取或者修改。

 

被数据访问逻辑组件暴露的方法可以执行以下类型的任务:

与管理“实体”的一般相关的功能性,如CRUD功能。

为只读目的,从多个表中获取数据的查询。数据的返回依赖于是否分页的需求,以流或者非流的方式作为结果,依赖于调用者是否从中可以获益。

 刷新数据和同时暗含返回数据的行为。

返回和实体架构有关的元数据,查询参数,结果集架构。

为用户界面的分页需要数据的子集,如,当滚动更宽的产品列表。

 

输入参数到数据访问逻辑组件方法典型包括标量(scalar)值和通过XML字符串或者DataSet表现的业务文档。返回的数据是标量的,DataSetDataReaderXML字符串,或者其它数据格式。为对象选择数据格式的特定设计和实现,见MSDN上的“Designing Data Tier Components and Passing Data Through Tiers (http://msdn.microsoft.com/library/?url=/library/en-us/dnbda/html/BOAGag.asp?frame=true)

 

数据访问逻辑组件的例子

下面的C#代码显示了一个简单的数据访问逻辑组件的部分轮廓,这个例子用于访问订单数据。这个代码不是有意作为你编码的模板,但可以说明我们讨论的一些概念。

 

public class OrderData

{

private string conn_string;

public OrderData()

{

// acquire the connection string from a secure or encrypted location

// and assign to conn_string

}

public DataSet RetrieveOrders()

{

public OrderDataSet RetrieveOrder(Guid OrderId)

{

// Code to return a typed DataSet named OrderDataSet

// representing a specific order.

// (OrderDataSet will have a schema that has been defined in Visual Studio)

}

public void UpdateOrder(DataSet updatedOrder)

{

// code to update the database based on the properties

// of the Order data sent in as a parameter of type dataset

}

}

 

数据访问逻辑组件设计的建议

当设计数据访问逻辑组件时,将要考虑以下一般的建议:

仅返回你需要的数据。这个可以改善性能和增加度量性。

使用存储过程来从前在的数据架构中抽取数据访问。然而,不要过度使用存储过程,因为如此做,会在代码的维护和重用方面产生对应用程序的维护很严格的影响。过度使用存储过程的一个征兆是持有很大的彼此调用存储结构的树。一定避免使用存储过程实现控制流,处理个别值(例如,执行字符串处理),或者用Transact-SQL处理困难的其它功能。

依赖于数据-敏感工作的RDBMS功能。遵循原则: “迁移处理到数据,而不是数据到处理。”需要平衡存储过程的使用与数据逻辑的重用性和维护性。

实现标准的,或者期望的一般功能的存储过程,如,插入,读取,刷新,和查找功能。如此做,当开发业务组件时,会节省时间。如果抢先性实现这些功能,要能够使实现保存一致和强行执行内部标准。如果设计是重复的,甚至能够使用代码产生器来构建基本的样板存储过程和数据访问逻辑组件逻辑。

在个别定义的接口中,或者基类中,暴露期望的功能是公共的横穿所有数据访问逻辑组件的。

为不同的客户端设计一致的接口:

Ø 业务组件可能用多种方法被实现,包括自定义.NET代码的使用,BizTalk 编排规则,或者第三方业务规则引擎。为数据访问逻辑组件设计的接口要兼容当前的和潜在的业务组件的需求,避免使用额外的接口,外观,或者它们之间的映射层。

Ø 基于ASP.NET的用户界面展现数据在性能方面的优势来源于DataReaderDataReader是仅超前的只读的最好操作,这样处理起每行数据是很快的。如果数据访问逻辑组件和界面是部署在一起,应该在数据访问逻辑组件返回DataReader来暴露大量的查询结果。如果打算长时间操作数据,使用非连接的DataSet代替DataReader来改善可度量性。

使数据访问逻辑组件暴露数据和操作它的元数据(例如,架构和列标题)。如此可以帮助使应用程序在运行时更灵活,特别是在用户界面里展现数据时。

不一定为每个表构建一个数据访问逻辑组件。为业务过程所使用,应该设计数据访问逻辑组件呈现的是轻量的高抽象和反向格式化(denormalization)。同样地,一般下不暴露关系表;相反地,在相关数据访问逻辑组件上,暴露关系功能作为数据的操作。例如,在书本和作者之间多对多关系的数据库中,很容易被TitleAuthor所实现,不需要为TitleAuthor创建数据访问逻辑组件,而是提供AddAuthor方法到Book数据访问逻辑组件。语义上可以增加一个本书给一位作者,或者为一本书增加一位作者,不需要“插入作者关系”。

如果存储加密数据,数据访问逻辑组件要执行解密(除非想让加密数据一成不变的推动客户端)。

如果在Enterprise ServiceCOM+)中宿主业务组件,数据访问逻辑组件应该作为服务组件构建,且把它作为类库应用程序部署在Enterprise Service。这个允许它们参与和明确的表决Enterprise Service事务,和使用基于角色的认证。如果不使用任何服务,或者不加载在和Enterprise Service调用者同样的AppDomain中,数据访问逻辑组件不需要被托管在Enterprise Service。有关使用Enterprise Service的更多信息,将本章前面的“业务组件和工作流”。

在你需要时,才给予事务处理的方法。不要标记所有的数据访问逻辑组件为“需要事务处理”,因为这会增加资源的负担,对用户界面的读取操作不是必需的。相反,通过增加下面的属性,标记它们是“支持事务处理”:[TransactionTransactionOption.Supported)]

为数据的查询考虑调整隔离层次。如果正在构建一个高吞吐量的应用程序,特别是数据的操作执行在底层面的隔离层。使隔离层结合起来可能对数据一致性会有负面的影响,所以,需要一个场景一个场景地小心分析这个选择。一般情况下,处理隔离层的事务只能被设在事务的根(那就是,业务处理组件)。更多信息,见本章前面的“设计业务层”。

使用数据访问帮助组件。这个方法的优势和明细民间本章的“设计数据访问帮助组件”。

 

有关设计数据访问逻辑组件的更多信息,见“.NET

Data Access Architecture Gride” (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/daag.asp)

微软也提供了数据访问应用程序块(http://msdn.microsoft.com/library/en-us/dnbda/html/daab-rm.asp),一个经过测试的,高性能的数据帮助组件,你可以用于你的应用程序中。

 

设计数据访问帮助组件

当应用程序需要大批量的数据访问逻辑组件来访问相同的数据源,你会发现,在每个数据访问逻辑组件中,需要实现一个相似的一般数据访问代码。这个逻辑的复制可以导致维护的问题,为数据访问问题的故障检修员造成困难。在一个数据访问帮助组件中集中一般的数据访问功能性会产生一个清晰的,更易于管理的设计。数据访问帮助组件提供一个容易的模式到一个基本的数据源。可以认为数据访问帮助组件是一般的,深入到数据源的调用者身边的外观。它们是典型的应用程序业务逻辑被执行的无知论者。通常,为一个给定的数据源,仅需要一个或者两个帮助组件。任何一个实现一批不同功能,访问服务。例如,当一个会允许流的大量数据输出的同时,另一个数据访问帮助组件让你调用存储过程。

 

如果正在设计的应用程序对数据源类型不可知(例如,能够从Oracle数据库切换到SQL Server数据库),可以通过拥有两个简单的数据访问帮助组件到达目的,但它们保留相似的接口。然而,要注意,改变数据源应该保证对应用程序进行额外的测试,“没有接触”的数据源对于大部分应用程序的透明度都是未知的目标,或许被第三方独立软件开发商开发的除外。

 

使用数据访问帮助组件的目的是:

从封装在数据访问逻辑组件的相关业务逻辑数据中抽取数据访问API程序模式,因此减少和简单化数据访问逻辑组件的代码。

隔离连接管理语义。

隔离数据源定位(通过连接字符串管理)。

隔离数据源审核。

隔离事务处理持续期间(当使用SQL Server访问数据,或者当使用ODBC或者LOEDB时,ADO.NET自动处理这个)。

为早期的维护集中数据访问逻辑,为遍及在开发团队中指定数据源代码的需要降低最小化,使它容易维护数据访问问题。

从数据访问逻辑组件中隔离数据访问API版本。

为数据访问监控和测试提供一个单一的拦截点。

使用代码访问,基于用户,或者基于角色的审核来约束对全部数据源的访问。

可以转换应用程序不能按常规方法处理数据源的非DotNET异常。

 

 MSDN上下载数据访问应用程序块,可以看到数据访问帮助组件的例子,包括源代码和文档。(http://msdn.microsoft.com/library/en-us/dnbda/html/daab-rm.asp)

 

访问多个数据源

    如果要访问Oracle数据库或者其它数据源,更愿意抽象出访问它们的差不多的可能的API。微软提供了数据库访问应用程序块的OracleOLE DB实现,且按照Nile性能标准环境对它进行了压力测试。你可以通过NSDN上的这篇文章(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/manprooracperf.asp下载这些实现。

 

    达到RDBM的透明性是个复杂的设计目标,使用数据访问帮助组件可以帮助减轻一些开发,充当故障检修员,维护的努力。然而,仍然需要测试每个数据源的应用程序,注意归结于不同的关系数据系统处理存储过程,游标和其它数据库工件的不同方法。

 

    如果幻想你的应用程序可以部署在不同的关系数据库管理系统,你应该实现用于相同接口的数据访问帮助组件,用工厂模式提供实际执行指定数据源的组件。前面的DotNET应用程序块的提及的改变源代码适合这些指定的需求。

 

和服务进行集成

如果业务处理包括外部服务,将需要处理和需要调用的每个服务的通讯语义。特别,需要使用正确的通讯API来调用服务,执行服务使用的数据和业务处理使用的数据之间的事务处理。如果服务契约有长期运行会话组成,在等待响应时,也需要保存中间状态。

 

     使用服务代理组件封装这些任务必须的逻辑,初始化和管理应用程序必须使用的每个基于消息的服务会话。可以把服务代理看作服务的数据访问逻辑组件,而不是数据存储;或者作为代理,或者访问其他服务的使者。有些服务发布者提供给调用者一个已经准备好的服务代理,在其它情况下,需要开发自己的服务代理。

 

使用服务代理的目的:

封装对一个服务的访问。

在数据格式和数据架构改变期间,隔离服务实现到业务处理实现。

提供业务组件调用服务兼容的输入和输出的数据格式。

 

    如果需要,服务代理也执行以下一般类型的任务:

执行与服务交换数据的基本验证。

为普通的查询缓存数据。

认证对服务的访问,从正在调用的应用程序的角度看,访问服务之前,提供一个细粒状的方法检查安全。典型地,服务也会认证和审核请求。

设置正确的安全上下文环境,或者提供提供正确的凭证给服务认证。例如,为调用的XML Web 服务设置凭证,可以使用HTTPCredentialCache

确保一部分消息是被正确的加密,或者需要时,构建一个安全的通道。

提供监控信息,允许和被提交的服务交互。这个允许确定合作者是否符合它们服务服务层协议(SLA)。

管理服务的异步会话

在一些情况下,需要应用程序和其它服务集成,二者发送和接受异步调用。在这种情况下,服务接口将被来自外面的服务接受调用,且应该设置调用是来自服务代理的。如果这些消息交换是实现在异步方法中,需要保持属于某批消息交换会话的跟踪。需要使用这两个选项的其中一个保持会话状态的跟踪:

在消息中使用业务数据识别会话。例如,在所有消息中使用订单ID识别在指定消息交换中处理的订单。这个一个与消息有关的非常直接的方法。

提供一个基础结构的组件,或者工具,产生GUID或者为指定的会话产生的ID,并匹配使它们和消息匹配。服务代理和服务接口需要访问这个信息,理解一个指定异步调用的解释。这个需要额外的开发,如果消息需要被外部服务解释,消息的上下文环境处于丢失状态。然而,如果想维护私有信息,可以方便使用自己相关的ID

 

有关这个主题的更多信息,见第3章,“安全,运行管理和通讯策略。”

 

下一步

这一章描述了在分布式应用程序和服务中为设计不同类型的组件的一般性建议。第3章,“安全,运行管理和通讯策略”讨论在设计应用程序或者服务方面的组织策略的冲突。