關於Dao層的設計我現在也還是有點模糊,大大小小的項目也做了五六個了,負責的資料庫設計也有三四個了。
在對Dao層進行設計時採用過兩種方案:
方案一:每一表對應一個Dao類(介面也可),每個Dao將完成對該表的增刪改查以及業務上要求的查詢操作。這麼設計的話如果表很多的話將會產生很多類,並且將會出現大量重複的代碼,因為每一個Dao中都將涉及到基礎的增刪改查。
方案二:寫一個基礎的類,可以完成基本的增刪改查,其他的對於業務上有額外需求的表單獨在寫一個類,不過這個類只包括額外的功能。這裡的基礎類寫的時候是需要嚴格注意的,因為採用的類似映射的實現,需要你把實體類設計的同表結構一摸一樣,因為在該類中對資料庫的增刪改查的Sql語句就是通過對實體類類名以及對實體類類中屬性的提取完形成的。
這裡給出一個基本的添加方法(vb.net實現):
Public Class SqlDao : Implements Dal.IDao
Private SqlDr As SqlDataReader
Private SqlCon As SqlConnection
Private SqlCmd As SqlCommand
'從設定檔app.config中取得串連資料庫的字串
Private strConnect As String = ConfigurationManager.AppSettings("strCon")
'得到類名
Private strClassName As String
'得到類的類型
Private mType As Type
'得到屬性集
Private mProS As PropertyInfo()
'在初始化方法中串連資料庫
'Public Sub Init(ByVal obj As Object) Implements IDao.Init
' SqlCon = New SqlConnection(strConnect)
' '在建構函式中對必要類型進行初始化
' strClassName = TypeName(obj)
' mType = obj.GetType()
' mProS = mType.GetProperties
'End Sub
'串連資料庫的一個私人方法
Private Function GetCon() As SqlConnection Implements IDao.GetCon
Try
If (SqlCon.State = ConnectionState.Closed) Then
SqlCon.Open()
End If
Catch ex As Exception
MsgBox("開啟資料庫時:" + ex.Message)
End Try
Return SqlCon
End Function
''' <summary>
''' 將對象添加到對應的表中,參數為對象,傳回值為Int型,表示影響的行數
''' </summary>
''' <param name="Entity "></param>
''' <returns>Integer</returns>
''' <remarks></remarks>
Public Function AddObj(Of T)(ByVal Entity As T) As Integer Implements IDao.AddObj
Dim res As Integer = 0 '用來返回該操作影響的行數
'定義單個屬性
Dim mPro As PropertyInfo
'定義sql參數
Dim para As SqlParameter
Dim strFields As String = ""
Dim strCondition As String = ""
Dim strSql As String = ""
For Each mPro In mProS
'該迴圈用來進行參數組合
'再添加時不用添加時間
strFields = CStr(Trim(mPro.GetValue(Entity, Nothing))) '擷取屬性值
If strFields <> "0" And strFields <> "00:00:00" And strFields <> "" Then
strSql = strSql + "@" + mPro.Name + ","
'組合形成欄位名
strCondition = strCondition + mPro.Name + ","
End If
Next
'最後再插入最後的括弧
strSql = Left(strSql, Len(strSql) - 1) + ")"
strCondition = Left(strCondition, Len(strCondition) - 1) + ")"
strSql = "INSERT INTO " + strClassName + " (" + strCondition + " VALUES (" + strSql
'MsgBox(strSql)
Try
Using sCmd As New SqlCommand(strSql, GetCon)
'設定執行方式
sCmd.CommandType = CommandType.Text
For Each mPro In mProS
'進行參數的賦值
'Dim stra As String = mPro.GetValue(obj, Nothing)
'一般的添加不用加入時間,除了下機表
strFields = CStr(Trim(mPro.GetValue(Entity, Nothing))) '擷取屬性值
If strFields <> "0" And strFields <> "00:00:00" And strFields <> "" Then
para = New SqlParameter("@" + mPro.Name, mPro.GetValue(Entity, Nothing))
sCmd.Parameters.Add(para)
End If
Next
res = sCmd.ExecuteNonQuery
End Using
Catch ex As Exception
MsgBox("進行對象添加時:" + ex.Message)
End Try
Return res '返回該操作影響的行數
End Function
End Class
這幾天從網上也查了一些資料主要就是關於Dao層該如何設計的問題,最直接的設計方案就是每一個表對應一個Dao,說是代碼重複太多,不過這樣設計那些基本的代碼是不用寫的,都有現成的工具,直接根據表產生對應的增刪改查。
不過因為需要重複的代碼太多了,因此有人提出這種方法:
public interface BaseDao<T> {
public void create (T t);
public void delete (T t);
public void update (T t);
}
public interface WindDao extends BaseDao<Wind> {
public void other (Wind wind);
}
將基本的增刪改查通過泛型放置到一個基礎的介面中,其他的只需實現該介面,如果有額外的需求便可自行添加方法。這可謂一個典型的繼承的應用。不過說實話,這種方法也不能使代碼量減少。
這塊還真是不太明白,論壇裡有人說:“其實可以將basedao注入baseservice來實現,這樣就不用每個dao都寫一個類了”,實在是理解不了,如果有大牛恰好經過勞煩指點一二,不勝感激。
曹師哥點撥:
遇到一個問題,我會採用軟體工程上的3w原則(what,why,how)來思考。
首先what:
dao(data access object),Data Access Objects,既然是對象那麼就有封裝,他封裝了業務及相關資料與資料庫進行互動的一系列的介面。
why:
1.使用者不需要瞭解這個對象細節,只需要瞭解這個對象的介面就可以資料庫進行互動,這樣方便了使用者的使用。
2.設計一個dao層,上面所有的業務層都調用這個dao層的介面,這樣就實現了軟體的重用性。
3.dao層的存在使得商務邏輯層跟訪問資料庫的代碼分開了。
4.dao層可以處理不同資料庫的差異性,使得軟體在oracle,mysql,db2等資料庫上遷移時改變代碼很少。
5.dao層的封裝不需要開發人員直接跟資料庫互動(有了dao層,通過dao層互動),增加了資料庫的安全性。等等
how:通過以上的why的分析,我們在設計dao層的時候,要注意:
1.提供豐富的介面供使用者調用,
2.在dao中不能涉及業務內容,一個dao層介面就對應一次資料庫操作(是原子性的)。
3.考慮軟體在不通資料庫上的遷移。
4.dao層是用來實現業務及相關資料和資料庫互動的橋樑,那麼dao層就需要對資料庫的操作進行一系列的封裝,包括增刪改查,資料庫的事務,預存程序,觸發器等等操作。其中有一點要注意的是事務的處理,dao層一般不負責事務的處理,把交易處理遺留給業務層來做。原因是:如果一次商務邏輯需要調用多個dao的方法,一旦某個dao的方法失敗,造成復原,則已經執行的那些DAO則無法復原。
總之,使用dao層,使得業務的操作跟資料庫的操作進行瞭解耦,業務的變化不會影響資料的訪問,而資料訪問方式的改變(保證介面不變),不會影響業務,使得系統的各個部分相互獨立。dao層的操作是對業務的一個分解,把一個完整的業務分解到資料庫中的相關表中。
原創文章,轉載請註明出處:http://www.the5fire.net/?p=168
本文固定連結:the5fire的技術部落格 | 如果喜歡我的部落格的話可以訂閱本博以便及時收到更新