溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

數(shù)據(jù)訪問層DAL是怎樣實(shí)現(xiàn)的

發(fā)布時間:2021-10-29 10:19:14 來源:億速云 閱讀:136 作者:柒染 欄目:編程語言

數(shù)據(jù)訪問層DAL的實(shí)現(xiàn)過程是怎么樣的,針對這個問題,這篇文章詳細(xì)介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

這里為了演示上簡單,假設(shè):后臺數(shù)據(jù)庫(暫為SqlServer只有用戶表User與部門表Department),各表字段相應(yīng)精簡:

User(用戶表)
Id主鍵
Name姓名
DeptId部門編號
其余字段省略......
Department(部門表)
Id主鍵
Name名稱
Desc部門描述
其余字段省略......

后臺數(shù)據(jù)庫:testdb的情況

數(shù)據(jù)訪問層DAL是怎樣實(shí)現(xiàn)的

建立相關(guān)的存儲過程:

數(shù)據(jù)訪問層DAL是怎樣實(shí)現(xiàn)的

一般我個人也喜歡ORM轉(zhuǎn)換成實(shí)體對象(見截圖)

數(shù)據(jù)訪問層DAL是怎樣實(shí)現(xiàn)的

數(shù)據(jù)訪問層DAL是怎樣實(shí)現(xiàn)的

(注意:這里增加了DeptTitle屬性<部門名稱>)

現(xiàn)在就是訪問數(shù)據(jù)庫SqlServer類型,封裝到SqlserverProvider中。如果將來訪問Access數(shù)據(jù)庫,對應(yīng)訪問封裝到AccessProvider中。

(Provider這里表示數(shù)據(jù)訪問提供程序)

數(shù)據(jù)訪問層DAL是怎樣實(shí)現(xiàn)的

SqlUserProvier專門實(shí)現(xiàn)對SqlServer的表User的操作,AccessUserProvider專門實(shí)現(xiàn)對Access的表User的操作,很顯然,操作功能都相同(增刪改查<CRUD>),因而對不同子類的相同部分抽象出來,形成父類(UserProvider)。

數(shù)據(jù)訪問層DAL是怎樣實(shí)現(xiàn)的

開始著手具體子類實(shí)現(xiàn):SqlUserProvider:UserProvider

數(shù)據(jù)訪問層DAL是怎樣實(shí)現(xiàn)的

(上圖數(shù)據(jù)庫連接串錯誤:單詞integrated才是正確的,***面調(diào)試錯誤后改正。)

我們發(fā)現(xiàn)重載的GetUsers方法,大量代碼重復(fù),進(jìn)行方法重構(gòu)(重復(fù)代碼重構(gòu)為方法GetUsersFromReader)!

數(shù)據(jù)訪問層DAL是怎樣實(shí)現(xiàn)的

繼續(xù)具體實(shí)現(xiàn)父類的抽象方法:GetUserById,發(fā)現(xiàn)該方法的部分代碼與先前的GetUsersFromReader方法中的部分代碼又重復(fù)了!

數(shù)據(jù)訪問層DAL是怎樣實(shí)現(xiàn)的

發(fā)現(xiàn)上圖紅色部分重復(fù)(該圖GetUserById方法忘記傳遞存儲過程所需的參數(shù)了),再接著方法重構(gòu),提煉重復(fù)的代碼,避免以后改動的多次修改。

數(shù)據(jù)訪問層DAL是怎樣實(shí)現(xiàn)的

接著編寫該類后續(xù)的方法(增/刪/改):(可以打開VS開發(fā)環(huán)境中的<服務(wù)器資源管理器>,連接上對應(yīng)的數(shù)據(jù)庫后,看存儲過程的參數(shù),以免編碼遺忘傳參)

數(shù)據(jù)訪問層DAL是怎樣實(shí)現(xiàn)的

接著也來看看 類:AccessUserProvider,見下圖

數(shù)據(jù)訪問層DAL是怎樣實(shí)現(xiàn)的

上圖GetUsers方法中的查詢語句沒有聯(lián)合查詢,后續(xù)會改動。(這里僅僅示范,其似Access是可以類似建立查詢表<后臺調(diào)用類似存儲過程方式>)

我們發(fā)現(xiàn)UserProvider的兩個子類的方法GetUserFromReader和GetUsersFromReader有重復(fù)代碼(僅僅是方法的參數(shù)不同) [想辦法抽象出來,放在父類中]

數(shù)據(jù)訪問層DAL是怎樣實(shí)現(xiàn)的

而方法的參數(shù)雖然是SqlDataReader與OleDbDataReader,但是查看定義,看到它們有自己的父類:DbDataReader。

public class SqlDataReader : DbDataReader, IDataReader, IDisposable, IDataRecord

public sealed class OleDbDataReader : DbDataReader

改寫父類:UserProvider

數(shù)據(jù)訪問層DAL是怎樣實(shí)現(xiàn)的

父類的方法加上修飾符protected,是為了確保只有子類能夠訪問。

子類便可以直接調(diào)用父類的方法了(GetUserFromReader和GetUsersFromReader方法),見截圖:

數(shù)據(jù)訪問層DAL是怎樣實(shí)現(xiàn)的

類似的完善SqlDepartmentProvider類和AccessDepartmentProvider類的代碼

(父類:DepartmentProvider提供保護(hù)方法GetDeparmentFromReader和GetDepartmentsFromReader)

數(shù)據(jù)訪問層DAL是怎樣實(shí)現(xiàn)的

每個具體的子類Provider都重復(fù)了屬性:ConnString,所以決定建一個父類:DataAccess來存放該屬性(UserProvider與DepartProvider都繼承自它),實(shí)際上DataAccess還可以包含其它的屬性和共用方法。

namespace抽象工廠模式.DAL  {  publicabstractclassDataAccess  {  privatestring_connString ="";  publicstringConnString  { get{ return_connString; } }  }  }

public abstract class UserProvider:DataAccess

public abstract class DepartmentProvider:DataAccess

通常:數(shù)據(jù)庫連接串的內(nèi)容都是存儲在對應(yīng)的配置文件中,而不硬編碼。

桌面應(yīng)用程序&mdash;[app.config],web應(yīng)用程序---[web.config],這里以app.config示例,數(shù)據(jù)庫連接串先按照SqlServer數(shù)據(jù)庫訪問的。

數(shù)據(jù)訪問層DAL是怎樣實(shí)現(xiàn)的

<?xml version="1.0" encoding="utf-8" ?> <configuration> <connectionStrings> <add name="DBConnString" connectionString="SERVER=.sqlexpress;DATABASE=testdb;INTEGRATED SECURITY=true"/> </connectionStrings> </configuration>

數(shù)據(jù)訪問層DAL是怎樣實(shí)現(xiàn)的

一定要手動引用:System.configuration,然后通過ConfigurationManager類來訪問連接串。

可以想象,根據(jù)數(shù)據(jù)庫的類型不同,實(shí)際底層操控的數(shù)據(jù)提供程序?yàn)镾ql__Provider或是Access__Provider。

但對于用戶調(diào)用者(業(yè)務(wù)邏輯層)只需要操控Provider就可以了。

假設(shè)我所在城市有兩個行政分區(qū)(東一區(qū)和西二區(qū)),有一家“真不錯”總店[經(jīng)營快餐系列的]在這兩個區(qū)都有連鎖店,對外統(tǒng)一電話:1111777。

(設(shè)一個總機(jī)號碼當(dāng)然方便了,總不至于將來開了10家分店,對外公布10個電話號碼,誰能記住???)

比如說:我現(xiàn)在餓了,想吃這家提供的“經(jīng)濟(jì)型快餐(一素<炒萵苣>一湯<豆腐湯>)”,我只要打電話111177,那邊只需要了解我的地址就可以了。(可以想象:知道了我的地址<就能明白所在行政區(qū),然后公司總店去指派所在區(qū)的分店來服務(wù)>),對于客戶我而言:如何指派哪家分店來服務(wù),以及經(jīng)濟(jì)型快餐如何制作的,我都不會關(guān)心的。我只關(guān)心:要好吃,然后要快點(diǎn)(畢竟,餓太久會受不了的。)

回到我們的程序:

UserProvider好比一個物品蔬菜<萵苣>,DepartmentProvider好比湯菜<豆腐>。Access文件夾[經(jīng)濟(jì)型],SqlServer文件夾[商務(wù)型] (你會問一個題外問題:有葷菜嗎?我的回答是:盡量別吃,如今都是激素喂出來的<現(xiàn)在人們消耗太快了,以前自然方式半年才能長大的動物,如今1個月人工方式就用激素喂成了>。吃多了,身體容易得病)。

只有一個問題:既然BLL(相對于DAL就是客戶調(diào)用者)只認(rèn)(UserProvider/DepartmentProvider),又是如何調(diào)用實(shí)際其作用的子類呢?

這就需要用到設(shè)計模式中的<簡單工廠模式> (具體選擇哪個子類實(shí)際上用父類來完成<根據(jù)客戶配置需求>)

數(shù)據(jù)訪問層DAL是怎樣實(shí)現(xiàn)的

當(dāng)然這里的配置文件:數(shù)據(jù)庫連接串和providerType需要匹配好。

父類:UserProvider我們提供靜態(tài)的Instance,來決定實(shí)際的子類(SqlUserProvider或者AccessUserProvider,根據(jù)配置文件的ProviderType的value來定)

數(shù)據(jù)訪問層DAL是怎樣實(shí)現(xiàn)的

如果將來出現(xiàn)了OracleUserProvider/DB2UserProvider/MySqlUserProvider/XmlUserProvider,這個藍(lán)色框框仍然需要增加case分支。這就不好了,需要再編碼(修改),好的設(shè)計方式應(yīng)該是對擴(kuò)展開放,對修改封閉。而且這里羅列出了所有的具體子類Provider,其實(shí)只需要一個子類Provider,但是其他的子類Provider也被迫出現(xiàn)在一起<大雜燴>(其實(shí)子類之間出現(xiàn)了耦合) 所以這種方式不可取,需要解決。

這里用反射的方式來解決這個問題。

首先約束:ProviderType的賦值需要規(guī)范,只能從(Sql/Access/DB2/MySql/Xml)選擇一個呢??梢园l(fā)現(xiàn):實(shí)際的子類名:ProviderType的值+“UserProvider”。

staticpublicUserProvider Instance  {  get {  if(_instance == null)  {  stringproviderTypeName=ConfigurationManager.AppSettings["ProviderType"]  +"UserProvider";  _instance =  Activator.CreateInstance(Type.GetType(providerTypeName)) asUserProvider;  }  return_instance;  }  }

如果:你的DAL是單獨(dú)用程序集方式建立的項(xiàng)目(類庫),請使用Assembly.Load等方式,這里由于是以文件夾方式組織的(DAL文件夾)<用Activator.CreateInstance可以O(shè)K.>

以后客戶端(BLL)調(diào)用的時候:比如刪除用戶表的記錄,就可以如下調(diào)用了:

UserProvider.Instance.DeleteUser(id)了。//這里BLL已經(jīng)不知道是由哪個子類(如SqlUserProvider)來實(shí)際工作的。

進(jìn)行一下測試,看是否運(yùn)行正常!

發(fā)現(xiàn)錯誤:一:數(shù)據(jù)庫連接串需要修改:

數(shù)據(jù)訪問層DAL是怎樣實(shí)現(xiàn)的

二:文件夾SqlServer改成Sql。以前的命名空間對應(yīng)改動下:

namespace抽象工廠模式.DAL.Provider.Sql

{

publicclassSqlDepartmentProvider:DepartmentProvider

&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;.

namespace抽象工廠模式.DAL.Provider.Sql

{

publicclassSqlUserProvider:UserProvider

&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;.

三:Type.GetType(需要完整的限定名)

數(shù)據(jù)訪問層DAL是怎樣實(shí)現(xiàn)的

測試通過:但發(fā)現(xiàn)沒有DeptTitle數(shù)據(jù),查找錯誤發(fā)現(xiàn)

publicUser(intid, stringname, intdeptId, stringdeptTitle)  {  this.Id = id;  this.Name = name;  this.DeptId = deptId;  this.DeptTitle = deptTitle; //DeptTitle;  }

數(shù)據(jù)訪問層DAL是怎樣實(shí)現(xiàn)的

附上:AccessUserProvider的代碼如下:

AccessUserProvider代碼

usingSystem;  usingSystem.Collections.Generic;  usingSystem.Text;  usingSystem.Data;  usingSystem.Data.OleDb;  using抽象工廠模式.DAL;  using抽象工廠模式.DAL.Entity;  namespace抽象工廠模式.DAL.Provider.Access  {  publicclassAccessUserProvider:UserProvider  {  publicoverrideList<User> GetUsers()  {  using(OleDbConnection conn = newOleDbConnection(ConnString))  {  vardbcmd = conn.CreateCommand();  dbcmd.CommandText = "GetUsers";  dbcmd.CommandType = CommandType.StoredProcedure;  conn.Open();  returnGetUsersFromReader(dbcmd.ExecuteReader());  }  }  publicoverrideList<User> GetUsers(intdeptId)  {  using(OleDbConnection conn = newOleDbConnection(ConnString))  {  vardbcmd = conn.CreateCommand();  dbcmd.CommandText = "GetUsersByDepartmentId";  dbcmd.CommandType = CommandType.StoredProcedure;  dbcmd.Parameters.Add("@DeptId", OleDbType.Integer).Value = deptId;  conn.Open();  returnGetUsersFromReader(dbcmd.ExecuteReader());  }  }  publicoverrideUser GetUserById(intid)  {  using(OleDbConnection conn = newOleDbConnection(ConnString))  {  vardbcmd = conn.CreateCommand();  dbcmd.CommandText = "GetUserById";  dbcmd.CommandType = CommandType.StoredProcedure;  dbcmd.Parameters.Add("@Id", OleDbType.Integer).Value =id ;  conn.Open();  returnGetUserFromReader(dbcmd.ExecuteReader());  }  }  publicoverrideboolDeleteUser(intid)  {  using(OleDbConnection conn = newOleDbConnection(ConnString))  {  OleDbCommand cmd = newOleDbCommand(  "delete from [user] where Id="+ id, conn);  conn.Open();  returncmd.ExecuteNonQuery() == 1;  }  }  publicoverrideintInsertUser(User user)  {  using(OleDbConnection conn = newOleDbConnection(ConnString))  {  OleDbCommand cmd = newOleDbCommand(  @"insert into [user](name,deptId) values(@id,@name);68select max(id) from [user] as newid",conn);  cmd.Parameters.Add("@id", OleDbType.Integer).Value = user.Id;  cmd.Parameters.Add("@name", OleDbType.VarChar).Value = user.Name;  conn.Open();  return(int)cmd.ExecuteScalar();  }  }  publicoverrideboolUpdateUser(User user)  {  using(OleDbConnection conn = newOleDbConnection(ConnString))  {  OleDbCommand cmd = newOleDbCommand(  "update [user] set name=@name,deptId=@deptid where Id=@id", conn);  cmd.Parameters.Add("@name", OleDbType.Integer).Value = user.Name;  cmd.Parameters.Add("@deptid", OleDbType.Integer).Value = user.DeptId;  cmd.Parameters.Add("@id", OleDbType.Integer).Value = user.Id;  conn.Open();  returncmd.ExecuteNonQuery() == 1;  }  }  }  }

后臺的testdb.mdb截圖:

數(shù)據(jù)訪問層DAL是怎樣實(shí)現(xiàn)的

關(guān)于數(shù)據(jù)訪問層DAL的實(shí)現(xiàn)過程是怎么樣的問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

dal
AI