实现数据访问功能是大多数使用NET Framework的开发人员的核心工作并且由他们生成的数据访问层是其应用程序必不可少的组成部分本文概述了五个建议希望您在使用Visual Studio NET和NET Framework生成数据访问层时予以考虑这些技巧包括通过使用基类来利用面向对象的技术和NET Framework基础结构通过遵循某些准则使类变得易于继承以及在就表示方法和外部接口进行决策之前仔细分析自己的需要
如果您要针对Microsoft NET Framework来开发以数据为中心的应用程序那么您终将需要创建数据访问层(DAL)您可能知道在NET Framework中生成代码带来的一些好处因为它同时支持实现和接口继承所以您的代码可以具有更高的可重用性尤其是可供您的组织中那些使用与Framework兼容的其他编程语言的开发人员重用在本文中我将介绍为了针对基于NET Framework的应用程序而开发DAL的五个规则在开始之前我要说明的是基于本文中讨论的规则生成的任何DAL都将与Windows平台上的开发人员所喜爱的传统的多层或N层应用程序兼容在该体系结构中表示层由对协调数据访问层工作的业务层进行调用的Web窗体Windows窗体或XML Web Service代码组成该层包含多个数据访问类另外在不需要进行业务处理协调的情况下表示层可能会直接对DAL进行调用该体系结构是传统的模型视图控制器(MVC)模式的变体并且在许多方面由Visual StudioNET及其公开的控件所采用
规则使用面向对象的功能
最基础的面向对象的任务是使用继承的实现来创建抽象基类该基类可以包含所有数据访问类可以通过继承使用的服务如果这些服务足够通用则可以通过在整个组织中分发基类来对它们进行重用例如在最简单的情况下基类可以为派生类完成连接对象的创建如图所示
Imports SystemDataSqlClient
Namespace ACMEData
Public MustInherit Class DALBase : Implements IDisposable
Private _connection As SqlConnection
Protected Sub New(ByVal connect As String)
_connection = New SqlConnection(connect)
End Sub
Protected ReadOnly Property Connection() As SqlConnection
Get
Return _connection
End Get
End Property
Public Sub Dispose() Implements IDisposableDispose
_connectionDispose()
End Sub
End Class
End Namespace
正如您在该图中看到的那样DALBase类被标记为MustInherit(在C#中为abstract)以确保它用于继承关系该类随后会包含一个在公共构造函数(它接受连接字符串作为参数)中实例化的私有SqlConnection对象然后受保护的Connection属性允许派生类访问该连接对象而IDisposable接口中的Dispose方法则确保该连接对象得以被处理即使是在下面这个简化的示例中您也可以从中注意到抽象基类的用处
Public Class WebData : Inherits DALBase
Public Sub New()
MyBaseNew(ConfigurationSettingsAppSettings(ConnectString))
End Sub
Public Function GetOrders() As DataSet
Dim da As New SqlDataAdapter(usp_GetOrders MeConnection)
daSelectCommandCommandType = CommandTypeStoredProcedure
Dim ds As New DataSet()
daFill(ds)
Return ds
End Function
End Class
在该示例中WebData类继承自DALBase因此它不需要考虑实例化SqlConnection对象的问题而只需通过MyBase关键字(或C#中的base关键字)将连接字符串传递给基类WebData类的GetOrders方法可以使用MeConnection(在C#中为thisConnection)访问受保护的属性尽管该示例相对简单但如果您看了规则和规则的话就会发现该基类还可以提供其他服务
当DAL需要在COM+环境中运行时抽象基类尤其有用在这种情况下因为允许组件使用COM+所需的代码更为复杂所以创建一个如图中所示的服务组件基类是有意义的
<ConstructionEnabled(True) _
Transaction(TransactionOptionSupported) _
EventTrackingEnabled(True)> _
Public MustInherit Class DALServicedBase : Inherits ServicedComponent
Private _connection As SqlConnection
Protected Overrides Sub Construct(ByVal s As String)
_connection = New SqlConnection(s)
End Sub
Protected ReadOnly Property Connection() As SqlConnection
Get
Return _connection
End Get
End Property
End Class
在该代码中DALServicedBase类基本上包含了与图中相同的功能但是它另外继承了SystemEnterpriseServices命名空间中的ServicedComponent并且包含了一些属性以指明该组件支持对象结构事务和统计信息跟蹤然后该基类负责捕捉在组件服务管理器中配置的结构字符串并再一次创建和公开SqlConnection对象需要注意的是当一个类从DALServicedBase继承时它还将继承属性的设置换句话说派生类也会将它的事务选项设置为Supported如果该派生类想要重写该行为则它可以在类级别重新定义该属性此外派生类还应该在适当位置对自身利用重载方法和共享方法主要有两种使用重载方法(具有多个签名的单个方法)的情况第一当方法需要接收改变其类型的参数时可以使用它们在Framework中这一类型的典型示例是SystemConvert类的方法例如ToString方法包括个接收一个参数的重载方法每个方法都具有不同的类型第二重载方法可以用来公开参数数量不断增加(但不一定是不同类型的参数)的签名这种类型的重载证明在DAL中非常有效因为可以使用它来公开用于数据检索和修改的备用签名例如可以重载GetOrders方法以便一个签名不接收任何参数并返回所有订单而另一个签名则接收一个表明调用方只打算检索特定客户订单的参数如下面的代码所示
Public Overloads Function GetOrders() As DataSet
Public Overloads Function GetOrders(ByVal customerId As Integer) As DataSet
在这种情况下良好的实现技巧是将GetOrders方法的功能抽象到一个可以由每个重载签名调用的私有或受保护的方法中还可以使用共享方法(在C#中为static方法)来展开可供数据访问类的所有实例访问的字段属性和方法尽管不能将共享成员与使用组件服务的类结合使用但是对于可以在数据访问类的共享构造函数中检索然后被所有实例读取的只读数据来说它们可能十分有用在对读/写数据使用共享成员时要特别小心这是因为多个执行线程可能会竞争使用对共享数据的访问权
规则遵守设计准则
在Visual Studio NET随附的联机文档中有一个标题为Design Guidelines for Class Library Developers的主题它不仅论述您应该遵循的重载成员构造函数和事件的模式而且还讨论了类属性和方法的命名约定您应该遵守命名约定的主要原因之一是NET Framework提供的交叉语言继承如果您要在Visual Basic NET中生成一个DAL基类则您需要确保那些使用与NET Framework兼容的其他语言的开发人员可以从它继承并能容易地理解它的工作方式按照我概述过的准则去做那么您的命名约定和结构将不会是特定于语言的了举个例子您会在本文的代码示例中注意到Camel大小写风格(首个单词小写并夹杂大写字母)用于方法的参数Pascal大小写风格(每个单词都大写)用于方法而基类则具有Base后缀以表示它是一个抽象类NET Framework设计准则的必然结果是常规设计模式就像Gang of Four撰写的Design Patterns(AddisonWesley )中所介绍的那些设计模式一样例如NET Framework使用了Observer模式的一个名为Event模式的变体(您在类中公开事件时应当遵循该模式)
规则利用基础结构
NET Framework包含一些可以帮助处理与基础结构相关的一般性任务(例如检测和异常处理)的类和结构通过基类将这些概念与继承相结合可能十分有用例如请考虑在SystemDiagnostics命名空间中公开的跟蹤功能除了Trace和Debug类该命名空间还包括从Switch和TraceListener派生的类Switch类—BooleanSwitch和TraceSwitch可以通过编程方式以及通过应用程序的配置文件而被配置为打开和关闭就TraceSwitch而言可以公开多个级别的跟蹤TraceListener类—TextWriterTraceListener和EventLogTraceListener将Trace和Debug方法的输出分别定向到文本文件和事件日志因此您可以将跟蹤功能添加到基类中以便派生类可以轻松地记录消息继而应用程序可以使用应用程序配置文件来控制是否启用跟蹤您可以通过包含一个BooleanSwitch类型的私有变量并在构造函数中将其实例化以将该功能添加到图所示的DALBase类中
Public Sub New(ByVal connect As String)
_connection = New SqlConnection(connect)
_dalSwitch = New BooleanSwitch(DAL Data Access Code)
End Sub
BooleanSwitch的参数包括它的名称和说明您随后可以添加一个受保护属性以便将开关打开和关闭并添加另一个受保护属性以便使用Trace对象的WriteLineIf方法来格式化和写入跟蹤消息
Protected Property TracingEnabled() As Boolean
Get
Ret