自然框架之?dāng)?shù)據(jù)訪問
以前也寫過幾篇關(guān)于數(shù)據(jù)訪問的,這里是***的總結(jié)。麻雀雖小五臟俱全,數(shù)據(jù)訪問也許不起眼,但是也要好好的設(shè)計一翻。從2004年開始用自己的數(shù)據(jù)訪問,一直到現(xiàn)在,經(jīng)歷過兩次大的改版,隨著需求的變化,也增加了不少的功能,小修小改那就更多了。目的就是能夠讓自己更輕松一點。整理思路、整理代碼,寫點東西,一個是給自己留個腳??;另外一個,說不定也許能夠給大家?guī)蛡€小忙。
目標(biāo):
簡單、好用、易擴展、穩(wěn)定、性能。
特點:
- 基于ADO.net 2.0 編寫,理論上可以支持多種數(shù)據(jù)庫,目前測試了SQL Server 和Access,一位朋友幫忙測試了MySQL。Orcale等其他數(shù)據(jù)庫沒有測試過。
- 使用非常簡單。
- 支持事務(wù)、存儲過程、參數(shù)化SQL等。
- 對存儲過程的參數(shù)進行封裝,更便于操作和更換數(shù)據(jù)庫。
- 如果運行是出現(xiàn)異常,可以把異常信息、出錯的SQL保存到文本文件里面,便于調(diào)試、修改錯誤。
- 可以方便的擴展相關(guān)功能,遵循關(guān)閉開放原則。
不承擔(dān)的責(zé)任:
不對SQL語句進行檢查。
不負責(zé)防止SQL注入。
不負責(zé)分頁。
圖示:
結(jié)構(gòu):
1、 兩個工廠
CommonFactory:生成Db系列的實例,比如DbConnection、DbCommand等。內(nèi)部使用。他們都是抽象基類不能直接new,需要相應(yīng)的子類的實例,比如new SqlConnection、new SqlCommand等。這個就需要根據(jù)當(dāng)前的需求(驅(qū)動類型)來確定了,也就是這個工廠的職責(zé)。
DALFactory:調(diào)用者使用的工廠,通過這個工廠,根據(jù)數(shù)據(jù)驅(qū)動類型,生成數(shù)據(jù)訪問的實例。
2、 主體部分
DataAccessLibrary:這個是數(shù)據(jù)訪問的核心部分,相當(dāng)于大樹的主干。定義了一個DbCommand Command,通過他來實現(xiàn)各種功能。
主體部分僅實現(xiàn)最基本的功能,定義內(nèi)部結(jié)構(gòu)、成員,實現(xiàn)輸入和輸出的功能。
輸入主要是ExecuteNonQuery。通過他來傳遞添加、修改、刪除的SQL語句(包括參數(shù)化SQL和存儲過程)。還有一個 ExecuteExists,用來判斷數(shù)據(jù)庫里是否存在指定的記錄。
輸出部分主要是ExecuteReader,這個大家都不陌生吧。其他的原則上都是通過擴展(配件)的方式來實現(xiàn),不過為了便于調(diào)用,還是增加了ExecuteString、T ExecuteScalar<T>(string text)兩個函數(shù)。這個對于我來說比較常用,所以就放在主體部分里面了。
另外可以通過子類來實現(xiàn)支持不同數(shù)據(jù)庫的差異的部分。
3、 配件部分
這個就比較多了,比如對事務(wù)的處理、對存儲過程的參數(shù)的封裝、對Json 的處理、對添加、修改用SQL(包括參數(shù)化SQL)的處理等。每一個都是一個“配件”,這樣就可以通過增加配件的方式增加需要的功能。比如以前是不支持Json格式的記錄的,但是想玩玩ajax,選擇json來傳遞數(shù)據(jù),那么就需要把提取出來的數(shù)據(jù)轉(zhuǎn)換Json格式。那么就可以增加一個“配件”,就是增加一個類,而不影響其他代碼。
增加功能,并不影響其他的代碼,這個就是對擴展開放,對修改關(guān)閉。
實例
- //發(fā)回復(fù)
- Reply.bodyUBB = Request.Form["Editor"];
- Reply.topicID = int.Parse(this.DataID);
- #region 驗證信息
- if (Reply.bodyUBB.Length < 10)
- {
- Functions.PageRegisterAlert(Page, "請?zhí)顚憙?nèi)容,或者內(nèi)容太短!至少也得寫10個字,對吧。");
- return;
- }
- #endregion
- #region 內(nèi)部字段
- int userID = int.Parse(UserInfo.UserID);
- string ip = Request.UserHostAddress;
- DateTime dateTime = DateTime.Now;
- string bodyHTML;
- #endregion
- #region 處理UBB
- bodyHTML = bodyUBB.Replace("\r", "<BR>");
- //其他略
- #endregion
- //開啟事務(wù)
- Dal.ManagerTran.TranBegin();
- ManagerParameter parm = Dal.ManagerParameter;
- #region 設(shè)置參數(shù)
- parm.ClearParameter();
- parm.AddNewInParameter("TopicID", Reply.topicID); //
- parm.AddNewInParameter("回復(fù)內(nèi)容", bodyUBB);
- parm.AddNewInParameter("內(nèi)容HTML", bodyHTML);
- parm.AddNewInParameter("回復(fù)人ID", userID);
- parm.AddNewInParameter("回復(fù)人IP", ip, 15);
- parm.AddNewInParameter("回復(fù)時間", dateTime);
- #endregion
- #region 保存回復(fù),表名:BBS_Reply
- Dal.ModifyData.InsertData("BBS_Reply");
- if (Dal.ErrorMessage.Length > 0)
- {
- //出現(xiàn)異常
- Functions.PageRegisterAlert(Page, "保存您發(fā)的回復(fù)的時候出現(xiàn)意外情況!");
- return;
- }
- #endregion
- string sql;
- #region 更新回復(fù)人的回復(fù)數(shù)量,回復(fù)時間,以及各種積分。
- sql = @"update BBS_Topic set 回復(fù)次數(shù) = 回復(fù)次數(shù) + 1 ,***回復(fù)時間 = GetDate(),
- ***回復(fù)人ID = {0}, where TopicID ={1}";
- Dal.ExecuteNonQuery(string.Format(sql, userID,topicID));
- if (Dal.ErrorMessage.Length > 0)
- {
- //出現(xiàn)異常
- Functions.PageRegisterAlert(Page, "更新回復(fù)數(shù)量的時候出現(xiàn)意外情況!");
- return;
- }
- #endregion
- #region 更新回復(fù)人的參與討論的帖子
- sql = "select top 1 UserInTopicID from BBS_UserInTopic where UserID ={0} and TopicID={1} ";
- string userInTopicID = Dal.ExecuteString(string.Format(sql, userID, topicID));
- sql = "select top 1 回復(fù)次數(shù) from BBS_Topic where TopicID={0} ";
- string reCount = Dal.ExecuteString(string.Format(sql, topicID)) ?? "0";
- int intintReCount = int.Parse(reCount);
- if (userInTopicID == null)
- {
- #region 沒有參與過,添加記錄
- parm.ClearParameter();
- parm.AddNewInParameter("UserID", userID);
- parm.AddNewInParameter("TopicID", topicID);
- parm.AddNewInParameter("***查看時間", dateTime);
- parm.AddNewInParameter("***查看回復(fù)數(shù)", intReCount);
- Dal.ModifyData.InsertData("BBS_UserInTopic");
- if (Dal.ErrorMessage.Length > 0)
- {
- //出現(xiàn)異常
- Functions.PageRegisterAlert(Page, "增加您參與討論的帖子的時候出現(xiàn)意外情況!");
- return;
- }
- #endregion
- }
- else
- {
- #region 參與過,修改記錄
- parm.ClearParameter();
- parm.AddNewInParameter("***查看時間", dateTime);
- parm.AddNewInParameter("***查看回復(fù)數(shù)", intReCount);
- Dal.ModifyData.UpdateData("BBS_UserInTopic", "UserInTopicID=" + userInTopicID);
- if (Dal.ErrorMessage.Length > 0)
- {
- //出現(xiàn)異常
- Functions.PageRegisterAlert(Page, "更新參與討論的帖子的時候出現(xiàn)意外情況!");
- return;
- }
- #endregion
- }
- #endregion
- //提交事務(wù)
- Dal.ManagerTran.TranCommit();
- //正常
- lblMsg.Text = "發(fā)表回復(fù)成功!感謝您的參與!1秒后重新加載帖子。";
- Functions.PageRegisterJavascript(Page, "reload()");
簡單寫一個,以論壇的回復(fù)為例,這個大家都熟悉,不是太簡單也不是很復(fù)雜。
這個沒有按照三層的方式來寫,因為我分不出來哪些是業(yè)務(wù)邏輯,哪些是數(shù)據(jù)訪問,都寫到一起了,呵呵。但是這并不是說數(shù)據(jù)訪問只能寫成這個樣子。這個只是一個具體的、綜合性的例子。也可以把他分一分,找到業(yè)務(wù)邏輯的部分,提取出去,放在業(yè)務(wù)層;把數(shù)據(jù)訪問的部分也提出出去,放在數(shù)據(jù)層。
這里僅僅是一個數(shù)據(jù)訪問的調(diào)用的示例,并不是說要不要分層。
原文出處:http://www.cnblogs.com/jyk/archive/2011/03/28/1998254.html
【編輯推薦】