国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

設(shè)計(jì).NET應(yīng)用程序數(shù)據(jù)訪問層五大原則

2019-11-17 04:40:06
字體:
供稿:網(wǎng)友
設(shè)計(jì).NET應(yīng)用程序數(shù)據(jù)訪問層五大原則
  摘要:大多數(shù)使用.NET框架組件工作的開發(fā)人員的一個(gè)核心工作是實(shí)現(xiàn)數(shù)據(jù)訪問功能,他們建立的數(shù)據(jù)訪問層(data access layer)是應(yīng)用程序的精華部分。本文概述了使用Visual Studio .NET和.NET框架組件建立數(shù)據(jù)訪問層需要考慮的五個(gè)想法。這些技巧包括通過使用基類(base class)利用面相對象技術(shù)和.NET框架組件基礎(chǔ)結(jié)構(gòu),使類輕易繼續(xù),在決定顯示方法和外部界面前仔細(xì)地檢驗(yàn)需求。  假如你正在建立以數(shù)據(jù)為中心(data-centric)的.NET框架組件應(yīng)用程序,你最終必須建立數(shù)據(jù)訪問層。也許你知道在.NET框架組件中建立自己的代碼有很多好處。因?yàn)樗С謱?shí)現(xiàn)和接口(interface)繼續(xù),你的代碼更輕易重復(fù)使用,非凡是被使用不同的框架組件兼容(Framework-compliant)語言的開發(fā)人員使用。本文我將概述為基于.NET框架組件的應(yīng)用程序建立數(shù)據(jù)訪問層的五條規(guī)則。

  開始前,我必須提醒你建立的任何基于本文討論的規(guī)則的數(shù)據(jù)訪問層必須與傳統(tǒng)Windows平臺(tái)上開發(fā)人員喜歡的多層或者n層應(yīng)用程序兼容。在這種結(jié)構(gòu)中,表現(xiàn)層包含Web窗體、Windows窗體、調(diào)用與數(shù)據(jù)訪問層的工作相應(yīng)的事務(wù)層的xml服務(wù)代碼。該層由多個(gè)數(shù)據(jù)訪問類(data access classe)組成。換句話說,在事務(wù)處理協(xié)調(diào)不是必要的情況下,表現(xiàn)層將直接調(diào)用數(shù)據(jù)訪問層。這種結(jié)構(gòu)是傳統(tǒng)的模型-視列表-控制程序(Model-View-Controller,MVC)模式的變體,在多種情況下被Visual Studio .NET和它暴露的控件采用。  規(guī)則1:使用面向?qū)ο筇匦?BR>
  最基本的面向?qū)ο笫聞?wù)是建立一個(gè)使用實(shí)現(xiàn)繼續(xù)的抽象類。這個(gè)基類可以包括你的所有數(shù)據(jù)訪問類通過繼續(xù)能夠使用的服務(wù)。假如那些服務(wù)足夠了,它們就能通過在整個(gè)組織的基類分布實(shí)現(xiàn)重復(fù)使用。例如最簡單的情況是基類能夠?yàn)檠苌愄幚磉B接的建立過程,如列表1所示。
Imports System.Data.SqlClientNamespace ACME.Data
Public MustInherit Class DALBase : Implements IDisposable
PRivate _connection As SqlConnectionProtected Sub New(ByVal connect As String)
_connection = New SqlConnection(connect)
End SubProtected ReadOnly Property Connection() As SqlConnection
Get
Return _connection
End Get
End PropertyPublic Sub Dispose() Implements IDisposable.Dispose
_connection.Dispose()
End SubEnd Class
End Namespace
列表1.簡單基類  在列表中可以看到,對DALBase類作了MustInherit標(biāo)記(C#中的抽象),以確保它在繼續(xù)關(guān)系中使用。接著該類在公共構(gòu)造函數(shù)中包括了一個(gè)實(shí)例化的私有SqlConnection對象,它接收連接字符串作為一個(gè)參數(shù)。當(dāng)來自IDisposable接口的Dispose方法確保連接對象已經(jīng)被配置了的時(shí)候,受保護(hù)的(protected)Connection屬性答應(yīng)衍生類訪問該連接對象。

  即使在下面簡化的例子中你也能開始看到抽象基類的用處:
Public Class WebData : Inherits DALBase
Public Sub New()
MyBase.New(ConfigurationSettings.AppSettings("ConnectString"))
End SubPublic Function GetOrders() As DataSet
Dim da As New SqlDataAdapter("usp_GetOrders", Me.Connection)
da.SelectCommand.CommandType = CommandType.StoredProcedure
Dim ds As New DataSet()da.Fill(ds)
Return ds
End Function
End Class  在這種情況下,WebData類繼續(xù)自DALBase,結(jié)果就是不必?fù)?dān)心實(shí)例化SqlConnection對象,而是通過MyBase要害字(或者C#中的基要害字)簡單地把連接字符串傳遞給基類。WebData類的GetOrders方法能使用Me.Connection(在C#中是this.Connection)訪問受保護(hù)的屬性。雖然這個(gè)例子相對簡單,但是你將在規(guī)則2和3中看到基類也提供了其它的服務(wù)。

  當(dāng)數(shù)據(jù)訪問層必須在COM+環(huán)境中運(yùn)行時(shí)抽象的基類很有用。在這種情況下,因?yàn)榇饝?yīng)組件使用COM+的必要代碼復(fù)雜得多,所以更好的方式是建立一個(gè)如列表2所示的服務(wù)組件(serviced component)基類。
<ConstrUCtionEnabled(True), _
Transaction(TransactionOption.Supported), _
EventTrackingEnabled(True)> _
Public MustInherit Class DALServicedBase : Inherits ServicedComponentPrivate _connection As SqlConnectionProtected Overrides Sub Construct(ByVal s As String)

_connection = New SqlConnection(s)
End SubProtected ReadOnly Property Connection() As SqlConnection
Get
Return _connection
End Get
End Property
End Class
列表2.服務(wù)組件基類  在這段代碼中,DALServicedBase類包含的基本功能與列表1中的相同,但是加上了從System.EnterpriseServices名字空間的ServicedComponent的繼續(xù),并且包括了一些屬性,指明組件支持對象構(gòu)造、事務(wù)和靜態(tài)跟蹤。接著該基類仔細(xì)地捕捉組件服務(wù)治理器(Component Services Manager)中的構(gòu)造字符串并且再次建立和暴露SqlConnection對象。我們要注重的是當(dāng)一個(gè)類繼續(xù)自DALServicedBase時(shí),它也繼續(xù)了屬性的設(shè)置。換句話說,一個(gè)衍生類的事務(wù)選項(xiàng)也設(shè)置為Supported。假如衍生類想重載這種行為,它能在類的層次重新定義該屬性。

  此外,衍生類在適當(dāng)情況下應(yīng)該有利于自身重載和共享方法。使用重載的方法(一個(gè)方法有多個(gè)調(diào)用信號(hào))在本質(zhì)上有兩種情況。首先,它們在一個(gè)方法需要接受多種類型的參數(shù)時(shí)使用。框架組件中的典型例子是System.Convert類的方法。例如ToString方法包含18個(gè)接受一個(gè)參數(shù)的重載方法,每個(gè)重載方法的類型不同。其次,重載的方法用于暴露參數(shù)數(shù)量不斷增長的信號(hào),而不是不同類型的必要參數(shù)。在數(shù)據(jù)訪問層中這類重載變得效率很高,因?yàn)樗苡糜跒閿?shù)據(jù)檢索和修改暴露交替的信號(hào)。例如GetOrders方法可以重載,這樣一個(gè)信號(hào)不接受參數(shù)并返回所有訂單,但是附加的信號(hào)接受參數(shù)以表明調(diào)用程序希望檢索特定的顧客訂單,代碼如下:
Public Overloads Function GetOrders() As DataSet
Public Overloads Function GetOrders(ByVal customerId As Integer) As DataSet  這種情況下的一個(gè)好的實(shí)現(xiàn)技巧是抽象GetOrders方法的功能到一個(gè)能被每個(gè)重載信號(hào)調(diào)用的私有的或者受保護(hù)的方法中。

  共享方法(C#中的靜態(tài)方法)也能用于暴露數(shù)據(jù)訪問類的所有實(shí)例能夠訪問的字段、屬性和方法。盡管共享成員不能與使用組件服務(wù)(Component Services)的類一起使用,但是對于在數(shù)據(jù)訪問類的共享構(gòu)造函數(shù)中檢索并被所有實(shí)例讀取的只讀數(shù)據(jù)是有用的。使用共享成員讀/寫數(shù)據(jù)時(shí)要小心,因?yàn)闉榱嗽L問該共享數(shù)據(jù),執(zhí)行的多個(gè)線程可能會(huì)競爭。   規(guī)則2:堅(jiān)持設(shè)計(jì)指導(dǎo)

  隨Visual Studio .NET一起發(fā)布的在線文檔中有一個(gè)叫"類庫開發(fā)人員的設(shè)計(jì)指導(dǎo)(Design Guidelines for Class Library Developers)"的主題,它覆蓋了類、屬性和方法的名字轉(zhuǎn)換,是重載的成員、構(gòu)造函數(shù)和事件的補(bǔ)充模式。
你必須遵循名字轉(zhuǎn)換的主要原因之一是.NET框架組件提供的跨語言(cross-language)繼續(xù)。假如你在Visual Basic .NET中建立一個(gè)數(shù)據(jù)訪問層基類,你想確保使用.NET框架組件兼容的其它語言的開發(fā)人員能繼續(xù)它并輕易理解它怎樣工作。通過堅(jiān)持我概述的指導(dǎo)方針,你的名字轉(zhuǎn)換和構(gòu)造就不會(huì)是語言特定的(language specific)。例如,你可能注重到在本文例子的代碼中第一個(gè)詞小寫,并加上intercaps是用于方法的參數(shù)的,每個(gè)詞大寫是用于方法的,基類使用Base標(biāo)志來標(biāo)識(shí)它是一個(gè)抽象類。

  可以推測.NET框架組件設(shè)計(jì)指導(dǎo)都是普通設(shè)計(jì)模式,像Gang of Four (Addison-Wesley, 1995)寫的Design Patterns記載的一樣。例如.NET框架組件使用了Observer模式的一個(gè)變體,叫做Event模式,在類中暴露事件時(shí)你必須遵循它。  規(guī)則3:利用基礎(chǔ)結(jié)構(gòu)(Infrastructure)

  .NET框架組件包括一些類和構(gòu)造,它們能輔助處理通常的與基礎(chǔ)結(jié)構(gòu)相關(guān)的事務(wù),例如裝置和異常處理。通過基類把這些概念與繼續(xù)組合起來將非常強(qiáng)大。例如,你能考慮一下System.Diagnostics名字空間中暴露的跟蹤功能。除了提供Trace和Debug類外,該名字空間還包括衍生自Switch和TraceListener的類。Switch類的BooleanSwitch和TraceSwitch能被配置用于打開和關(guān)閉應(yīng)用程序和配置文件,在TraceSwitch中可以暴露多層次跟蹤。TraceListener類的TextWriterTraceListener和EventLogTraceListener分別將Trace和Debug方法的輸入定位到文本文件和事件日志。

  這樣作的結(jié)果是給基類添加了跟蹤功能,使衍生類記錄消息日志更簡單。接著應(yīng)用程序能使用配置文件控制是否答應(yīng)跟蹤。你能包括一個(gè)BooleanSwitch類型的私有變量并在構(gòu)造函數(shù)中實(shí)例化它來給列表1中的DALBase添加這個(gè)功能:
Public Sub New(ByVal connect As String)
_connection = New SqlConnection(connect)
_dalSwitch = New BooleanSwitch("DAL", "Data Access Code")
End Sub  傳遞給BooleanSwitch的參數(shù)包括名字和描述。接著你能添加一個(gè)受保護(hù)的屬性打開和關(guān)閉開關(guān),也能添加一個(gè)屬性使用Trace對象的WriteLineIf方法格式化并寫入跟蹤消息:

Protected Property TracingEnabled() As Boolean
Get
Return _dalSwitch.Enabled
End Get
Set(ByVal Value As Boolean)
_dalSwitch.Enabled = Value
End Set
End PropertyProtected Sub WriteTrace(ByVal message As String)
Trace.WriteLineIf(Me.TracingEnabled, Now & ": " & message)
End Sub   通過這種途徑,衍生類自己并不知道開關(guān)(switch)和監(jiān)聽(listener)類,當(dāng)數(shù)據(jù)訪問類產(chǎn)生一個(gè)有意義的信號(hào)時(shí)能夠簡單地調(diào)用WriteTrace方法。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.diagnostics>
<switches>
<add name="DAL" value="1" />
</switches>
<trace autoflush="true" indentsize="4">
<listeners>
<add name="myListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="DALLog.txt" />
</listeners>
</trace>
</system.diagnostics>
</configuration>
列表3.跟蹤的配置文件  為了建立一個(gè)監(jiān)聽器并打開它,需要使用應(yīng)用程序配置文件。列表3顯示了一個(gè)簡單的配置文件,它能夠打開剛才顯示的數(shù)據(jù)訪問類開關(guān),并通過myListener調(diào)用TextWriterTraceListener把輸出定位到文件DALLog.txt中。當(dāng)然,你能通過從TraceListener類衍生程序化地建立監(jiān)聽器并把該監(jiān)聽器直接包含在數(shù)據(jù)訪問類中。
Public Class DALException : Inherits applicationException
Public Sub New()
MyBase.New()
End SubPublic Sub New(ByVal message As String)
MyBase.New(message)
End SubPublic Sub New(ByVal message As String, ByVal innerException As
Exception)
MyBase.New(message, innerException)
End Sub
'在這兒添加自定義成員
Public ConnectString As String
End Class
列表4.自定義異常類  你從中收益的第二個(gè)基礎(chǔ)結(jié)構(gòu)是結(jié)構(gòu)化異常處理(SEH)。在最基本的層次,數(shù)據(jù)訪問類能夠暴露它的衍生自System.ApplicationException 的Exception(異常)對象并能進(jìn)一步暴露自定義成員。例如,列表4中顯示的DALException對象能用于包裝數(shù)據(jù)訪問類中的代碼產(chǎn)生的異常。接著基類能暴露一個(gè)受保護(hù)的方法包裝該異常,組裝自定義成員,并把它發(fā)回給調(diào)用程序,如下所示:
Protected Sub ThrowDALException(ByVal message As String, _
ByVal innerException As Exception)
Dim newMine As New DALException(message, innerException)newMine.ConnectString = Me.Connection.ConnectionString
Me.WriteTrace(message & "{" & innerException.Message & "}")
Throw newMine
End Sub  使用這種方法,衍生類能簡單地調(diào)用受保護(hù)的方法,傳遞進(jìn)去一個(gè)特定的數(shù)據(jù)異常(典型的有SqlException或者 OleDbException),該異常被截取并添加了從屬于特定數(shù)據(jù)域的消息。基類在DALException中包裝該異常并把它發(fā)回到調(diào)用程序。這就答應(yīng)調(diào)用程序用一個(gè)Catch語句輕易地捕捉所有來自數(shù)據(jù)訪問類的異常。

  作為選擇之一,你可以看一看MSDN上發(fā)布的"Exception Management Application Block Overview"。該框架組件通過一系列對象結(jié)合了異常和應(yīng)用程序日志記錄。實(shí)際上,通過從.NET 框架組件提供的BaseApplicationException類衍生的自定義異常類能夠簡單地插入該框架組件。   規(guī)則4:仔細(xì)選擇外部界面

  在你設(shè)計(jì)數(shù)據(jù)訪問類的方法時(shí),需要考慮它們怎樣接受和返回?cái)?shù)據(jù)。對大多數(shù)開發(fā)人員來說,主要有三個(gè)選擇:直接使用ADO.NET對象、使用XML、使用自定義類。

  假如直接暴露ADO.NET對象,你能使用一到兩個(gè)編程模型。第一個(gè)包括數(shù)據(jù)集和數(shù)據(jù)表對象,它們對不連接數(shù)據(jù)訪問很有用。有很多關(guān)于數(shù)據(jù)集和與它關(guān)聯(lián)的數(shù)據(jù)表的文章,但是當(dāng)你必須使用從下層數(shù)據(jù)存儲(chǔ)斷開的數(shù)據(jù)時(shí)它才最有用處。換句話說,數(shù)據(jù)集能在應(yīng)用程序各層之間傳遞,即使那些層在物理上是分布式的,當(dāng)業(yè)務(wù)和數(shù)據(jù)服務(wù)層放置在同一群服務(wù)器上并且與表現(xiàn)服務(wù)分開時(shí)也能使用。此外,數(shù)據(jù)集對象是通過基于XML的Web服務(wù)返回?cái)?shù)據(jù)的理想方法,因?yàn)樗鼈兪强纱谢模虼四茉赟OAP回應(yīng)消息中返回。


  這與使用實(shí)現(xiàn)IDataReader接口的類(例如SqlDataReader 和OleDbDataReader)訪問數(shù)據(jù)不同。數(shù)據(jù)閱讀器(data reader)用只向前的,只讀的方式訪問數(shù)據(jù)。兩者之間最大的不同是數(shù)據(jù)集和數(shù)據(jù)表對象能在應(yīng)用程序域之間傳遞,通過傳遞值(by value)實(shí)現(xiàn),然而數(shù)據(jù)閱讀器能在各處傳遞,但是一般通過引用(by reference)實(shí)現(xiàn)。在列表5中,Read和GetValues在服務(wù)器過程中執(zhí)行并且它們的返回值復(fù)制到客戶端。

        設(shè)計(jì).NET應(yīng)用程序數(shù)據(jù)訪問層五大原則
  圖1.遠(yuǎn)程數(shù)據(jù)閱讀器

  該圖顯示了數(shù)據(jù)閱讀器怎樣存活在應(yīng)用程序域中,它在那兒它被建立,并且對它的所有訪問結(jié)果都在客戶端和服務(wù)器應(yīng)用程序域之間的循環(huán)之中。這意味著當(dāng)數(shù)據(jù)訪問方法在相同的應(yīng)用程序域運(yùn)行時(shí),應(yīng)該返回?cái)?shù)據(jù)閱讀器作為調(diào)用者。

  使用數(shù)據(jù)閱讀器時(shí)有兩個(gè)問題需要考慮。首先,當(dāng)你從數(shù)據(jù)訪問類的一個(gè)方法返回?cái)?shù)據(jù)閱讀器時(shí),你必須考慮與數(shù)據(jù)閱讀器關(guān)聯(lián)的連接對象的生存期。默認(rèn)情況是當(dāng)調(diào)用程序通過數(shù)據(jù)閱讀器重復(fù)時(shí)連接仍然是忙的,不幸的是當(dāng)調(diào)用程序結(jié)束后,連接仍然打開,因此它不返回到連接池(假如答應(yīng)連接池)。但是,當(dāng)通過傳遞CommandBehavior.CloseConnection 枚舉給command對象的ExecuteReader方法,連接的Close方法被調(diào)用時(shí),你能命令數(shù)據(jù)閱讀器關(guān)閉它的連接。

  其次,為了把表現(xiàn)層從特定的框架組件數(shù)據(jù)提供程序(例如SqlClient或者OleDb)中分離出來,調(diào)用代碼應(yīng)該使用IDataReader接口(例如SqlDataReader)而不是具體類型來引用返回值。通過這種方法,假如應(yīng)用程序后端從Oracle移植到 SQL Server,或者數(shù)據(jù)訪問類的一個(gè)方法的返回類型改變了,表現(xiàn)層也不需要更改。

  假如你希望數(shù)據(jù)訪問類返回XML,你可以從System.Xml名字空間中的XmlDocument和XmlReader中選擇一個(gè),它與數(shù)據(jù)集和IDataReader類似。換句話說,當(dāng)數(shù)據(jù)從數(shù)據(jù)源斷開時(shí)你的方法應(yīng)該返回一個(gè)XmlDocument(或者XmlDataDocument),然而XmlReader可用于訪問XML數(shù)據(jù)的流。

  最后,你也能決定與公共屬性一起返回自定義類。這些類可以使用Serialization(串行化)屬性標(biāo)記,這樣它們就能跨越應(yīng)用程序域復(fù)制。另外,假如你從方法中返回多個(gè)對象,就需要強(qiáng)化類型(strongly typed)的集合類。
Imports System.Xml.Serialization<Serializable()> _
Public Class Book : Implements IComparable
<XmlAttributeAttribute()> Public ProductID As Integer
Public ISBN As String
Public Title As String
Public Author As String
Public UnitCost As Decimal
Public Description As String
Public PubDate As DatePublic Function CompareTo(ByVal o As Object) As Integer _
Implements IComparable.CompareTo
Dim b As Book = CType(o, Book)
Return Me.Title.CompareTo(b.Title)
End Function
End ClassPublic NotInheritable Class BookCollection : Inherits ArrayList
Default Public Shadows Property Item(ByVal productId As Integer) _
As Book
Get
Return Me(IndexOf(productId))
End Get
Set(ByVal Value As Book)
Me(IndexOf(productId)) = Value
End Set
End PropertyPublic Overloads Function Contains(ByVal productId As Integer) As _
Boolean
Return (-1 <> IndexOf(productId))
End FunctionPublic Overloads Function IndexOf(ByVal productId As Integer) As _
Integer
Dim index As Integer = 0
Dim item As BookFor Each item In Me
If item.ProductID = productId Then
Return index
End If
index = index + 1
Next
Return -1
End FunctionPublic Overloads Sub RemoveAt(ByVal productId As Integer)
RemoveAt(IndexOf(productId))
End SubPublic Shadows Function Add(ByVal value As Book) As Integer
Return MyBase.Add(value)
End Function
End Class
列表6.使用自定義類
  上列表(列表6)包含了一個(gè)簡單的Book類和與它關(guān)聯(lián)的集合類的例子。你能注重到Book類用Serializable做了標(biāo)記,使它跨越應(yīng)用程序域能使用"by value"語法。該類實(shí)現(xiàn)了IComparable接口,因此當(dāng)它包含在一個(gè)集合類中的時(shí)候,默認(rèn)情況下它將按Title排序。BookCollection類從System.Collections名字空間的ArrayList衍生,并且為了將該集合限制到Book對象而隱藏了Item屬性和ADD方法。


  通過使用自定義類你完全地控制了數(shù)據(jù)的表現(xiàn)、開發(fā)人員的效率并且沒有依靠ADO.NET的調(diào)用。但是這種途徑需要更多的代碼,因?yàn)?NET框架組件沒有包含任何與對象相關(guān)的技術(shù)映射。在這種情況下,你應(yīng)該在數(shù)據(jù)訪問類中建立一個(gè)數(shù)據(jù)讀取器并使用它來組合自定義類。   規(guī)則5:抽象.NET框架組件數(shù)據(jù)提供程序

  最后一條規(guī)則說明了為什么和怎樣抽象數(shù)據(jù)訪問類內(nèi)部使用的.NET框架組件數(shù)據(jù)提供程序(data provider)。先前我說過ADO.NET編程模型暴露了特定的.NET框架組件數(shù)據(jù)提供程序,包括SqlClient、OleDb和其它MSDN Online Web站點(diǎn)上可用的。但是這種設(shè)計(jì)的結(jié)果是提高性能,為數(shù)據(jù)提供程序暴露特定數(shù)據(jù)源功能的能力,它強(qiáng)迫你決定使用那種數(shù)據(jù)提供程序編碼。換句話說,開發(fā)人員典型地會(huì)選擇使用SqlClient或OleDb,接著在各自的名字空間直接對它們的類進(jìn)行編程。

  假如你想改變.NET框架組件數(shù)據(jù)提供程序,你必須重新編寫數(shù)據(jù)訪問方法。為了避免這種情況發(fā)生,你可以使用Abstract Factory設(shè)計(jì)模式。使用這種模式,你能建立一個(gè)簡單的類,它暴露方法來建立主要的.NET框架組件數(shù)據(jù)提供程序?qū)ο螅╟ommand、connection、data adapter和parameter),而那些對象基于傳遞給構(gòu)造函數(shù)的.NET框架組件數(shù)據(jù)提供程序的信息。列表7中的代碼就是這樣一個(gè)簡單的類。
public enum ProviderType :int {SqlClient = 0, OLEDB = 1}public class ProviderFactory {
public ProviderFactory(ProviderType provider) {
_pType = provider;
_initClass();
}public ProviderFactory() {
_initClass();
}

private ProviderType _pType = ProviderType.SqlClient;
private bool _pTypeSet = false;
private Type[] _conType, _comType, _parmType, _daType;
private void _initClass() {
_conType = new Type[2];
_comType = new Type[2];
_parmType = new Type[2];
_daType = new Type[2];// 為提供程序初始化類型
_conType[(int)ProviderType.SqlClient] = typeof(SqlConnection);
_conType[(int)ProviderType.OLEDB] = typeof(OleDbConnection);
_comType[(int)ProviderType.SqlClient] = typeof(SqlCommand);
_comType[(int)ProviderType.OLEDB] = typeof(OleDbCommand);
_parmType[(int)ProviderType.SqlClient] = typeof(SqlParameter);
_parmType[(int)ProviderType.OLEDB] = typeof(OleDbParameter);
_daType[(int)ProviderType.SqlClient] = typeof(SqlDataAdapter);
_daType[(int)ProviderType.OLEDB] = typeof(OleDbDataAdapter);
}public ProviderType Provider {
get {
return _pType;
}
set {
if (_pTypeSet) {
throw new ReadOnlyException("Provider already set to "
+ _pType.ToString());
}
else {
_pType = value;
_pTypeSet = true;
}
}
}
public IDataAdapter CreateDataAdapter(string commandText,IDbConnection
connection) {
IDataAdapter d;
IDbDataAdapter da;

d = (IDataAdapter)Activator.CreateInstance(_daType[(int)_pType],
false);
da = (IDbDataAdapter)d;
da.SelectCommand = this.CreateCommand(commandText, connection);
return d; }

public IDataParameter CreateParameter(string paramName, DBType
paramType) {
IDataParameter p;
p = (IDataParameter)Activator.CreateInstance(_parmType[(int)_pType],

false);
p.ParameterName = paramName;
p.DbType = paramType;
return p;
}

public IDataParameter CreateParameter(string paramName, DbType
paramType, Object value) {
IDataParameter p;
p = (IDataParameter)Activator.CreateInstance(_parmType[(int)_pType],
false);
p.ParameterName = paramName;
p.DbType = paramType;
p.Value = value;
return p;
}

public IDbConnection CreateConnection(string connect) {
IDbConnection c;
c = (IDbConnection)Activator.CreateInstance(_conType[(int)_pType],
false);
c.ConnectionString = connect;
return c;
}

public IDbCommand CreateCommand(string cmdText, IDbConnection
connection) {
IDbCommand c;
c = (IDbCommand)Activator.CreateInstance(_comType[(int)_pType],
false);
c.CommandText = cmdText;
c.Connection = connection;
return c;
}
}
列表7. ProviderFactory  為了使用該類,數(shù)據(jù)訪問類的代碼必須對多個(gè).NET框架組件數(shù)據(jù)提供程序?qū)崿F(xiàn)的接口(包括IDbCommand、IDbConnection、IDataAdapter和IDataParameter)進(jìn)行編程。例如,為了使用一個(gè)參數(shù)化存儲(chǔ)過程的返回值來填充數(shù)據(jù)集,必須在數(shù)據(jù)訪問類的某個(gè)方法中有下面的代碼:
Dim _pf As New ProviderFactory(ProviderType.SqlClient)
Dim cn As IDbConnection = _pf.CreateConnection(_connect)
Dim da As IDataAdapter = _pf.CreateDataAdapter("usp_GetBook", cn)Dim db As IDbDataAdapter = CType(da, IDbDataAdapter)
db.SelectCommand.CommandType = CommandType.StoredProcedure
db.SelectCommand.Parameters.Add(_pf.CreateParameter("@productId",DbType.Int32, id))Dim ds As New DataSet("Books")
da.Fill(ds)  典型的情況是你在類的層次聲明ProviderFactory變量并在數(shù)據(jù)訪問類的構(gòu)造函數(shù)中實(shí)例化它。另外,它的構(gòu)造函數(shù)與從配置文件中讀取的提供程序一起組裝,而不應(yīng)該是硬代碼。你可以想象,ProviderFactory是數(shù)據(jù)訪問類的一個(gè)重大的補(bǔ)充,并且能被包括進(jìn)部件,分發(fā)給其它的開發(fā)人員。  結(jié)論

  在Web服務(wù)時(shí)代將建立越來越多的應(yīng)用程序操作來自獨(dú)立的應(yīng)用程序?qū)拥臄?shù)據(jù)。假如你遵循一些基本規(guī)則并形成習(xí)慣,編寫數(shù)據(jù)訪問代碼將更快、更輕易,并且更能重新使用,把你的錯(cuò)誤保存到服務(wù)器,答應(yīng)你保持?jǐn)?shù)據(jù)獨(dú)立。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 体育| 衡南县| 青田县| 博兴县| 云林县| 鄱阳县| 平果县| 临江市| 荔浦县| 昌平区| 桐乡市| 崇礼县| 武宣县| 石楼县| 通州市| 屯昌县| 彭泽县| 淳安县| 杭锦旗| 射洪县| 东海县| 西华县| 搜索| 乌海市| 凤凰县| 新巴尔虎右旗| 平利县| 凉城县| 普洱| 黎川县| 青岛市| 新宾| 泸定县| 陇南市| 临西县| 南投市| 湄潭县| 溧阳市| 远安县| 家居| 康定县|