探討.NET數(shù)據(jù)訪問層相關(guān)基礎(chǔ)結(jié)構(gòu)設(shè)計原則
.NET數(shù)據(jù)訪問層基礎(chǔ)結(jié)構(gòu)設(shè)計目標:
1.完成面向?qū)ο蟮臄?shù)據(jù)訪問
2.減少調(diào)用側(cè)代碼量
3.滿足可擴展的系統(tǒng)需求
4.保證數(shù)據(jù)一致性
其中,對于.NET訪問層基礎(chǔ)結(jié)構(gòu)設(shè)計,采用如下原則。
1.對于面向?qū)ο笙到y(tǒng),采用DataReader方式進行數(shù)據(jù)讀取;
2.為了減少調(diào)用側(cè)代碼量和滿足可擴展的系統(tǒng)需求,采用反射實現(xiàn)動態(tài)的屬性訪問;
作者參與系統(tǒng)使用Codeplex的項目FastReflection作為反射工具,對于對象基本屬性可通過屬性名字符串直接訪問,
例,Teacher類有屬性ClassID,我們可通過teacher.Item("ClassID")對其進行讀寫;
很多人擔心反射的效率問題,當然自己每次生成屬性訪問器可達到只有4倍的效率低下,而直接使用FastReflection可能會達到近40倍的效率低下;但1000000次讀寫在0.7秒內(nèi)完成與可擴展的目標權(quán)衡起來,還是可以采用的。
3.為了保證數(shù)據(jù)的一致性,我們采用每個數(shù)據(jù)表都有物理主鍵ID,類型為GUID的設(shè)計;同時使用DateTime型UpdDateTime字段來記錄插入和更新時間,作為排他的基本條件。
如何保證數(shù)據(jù)排他:
用戶A和用戶B同時取得一條數(shù)據(jù)進行更新的同時,使用UpdDateTime作為條件,如果UpdDateTime一致則可進行更新;
反之,無法進行更新。
在編碼中,我們使用ExecuteNonQuery執(zhí)行更新SQL文,而對返回的影響件數(shù)進行判斷;對于影響零件的情況,視為數(shù)據(jù)不一致的更新行為,報排他異常。
對于主鍵的使用:
小型系統(tǒng)一般都使用自動增長唯一標識列,都是提交數(shù)據(jù)后查詢主鍵,使用SQLServer2005以上的系統(tǒng),可以通過如下SQL文和輸出參數(shù)獲得自動增長的主鍵值:
- INSERTCategories(CategoryName)Values(@CategoryName)SET@Identity=SCOPE_IDENTITY()
其中輸出參數(shù)@Identity就是返回的自動增長主鍵值。
而對于比較復(fù)雜的系統(tǒng),如包含部分更新及全部更新和主細表同時更新的情況下,需要自己在服務(wù)器端進行主鍵設(shè)置,此種情況建議把主鍵類型設(shè)置為GUID型而不使用自動生成屬性,這樣就可以在更新執(zhí)行之前設(shè)置主表數(shù)據(jù)主鍵以及詳細表數(shù)據(jù)的外鍵并進行更新了。
4.事務(wù)控制方面,主要使用隱式事務(wù)在業(yè)務(wù)邏輯層就將事務(wù)開啟。
5.對于.NET數(shù)據(jù)庫訪問層建議大家多使用EnterpriseLibarary的數(shù)據(jù)訪問組件,優(yōu)化方面可以根據(jù)自己的設(shè)計進行,同時可以使用AOP組件對結(jié)構(gòu)進行優(yōu)化,我們自己的項目使用PostSharp對所有層的異常處理和日志輸出進行了優(yōu)化。
【編輯推薦】