這篇文章本來應該很早就寫出來的,但是一直苦於自己的精神能力有限,而且已經到了我們學校的考試周,所以時間上還是有點緊迫。關鍵的一點就是,找不到合理的思路來寫,思路沒有的話,就算是再好的素材,也寫不來大家喜歡的文章。
之前已經寫過關於.NET三層架的兩篇文章了,一篇是《【ASP.NET開發】ASP.NET(MVC)三層架構知識的學習總結》和《【ASP.NET開發】ASP.NET對SQLServer的通用數據庫訪問類》。如果大家有興趣的話,可以去讀一讀。當然了,這兩篇文章的內容,大部分都不是自己的,自己也是看了別人的博文,然后自己總結一下,拿過來自己用罷了。這次的文章主要是自己親自使用這些知識做了一個項目(我們學校資環學院的院網站),然后拿出來跟大家分享一下。也不要期望博主能夠寫出多么有水平的文章,我還是學生(大三),我也是在學習的過程中,寫博客之不過是想記錄自己學習過程中的點滴和記錄自己的進步,如果能夠順便的幫助別人學習就更好了。同時也希望大家能夠多給我提意見。
非常感謝 @ 守護晴天 ,@Adming,@ Qlin等博友給我提出的寶貴的修改意見。也希望大家在閱讀本博文的時候,如果有什么問題,或者疑問及時的給我留言溝通,大家一起探討。
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
對於三層架構來說,主要是使用設計模式的思想,對於項目的各個模塊實現"高內聚,低耦合"的思想。這里就不做詳細的介紹了,如果大家有興趣,可以閱讀軟件工程和設計模式相關文章。
對於三層架構來說,就是使用類,把我們在做項目的過程中,可能需要反復操作數據庫,反復的使用某個方法等等,可能就是操作的參數不同。如果我們如果在每次使用的時候,都去編寫相應的代碼,無疑會增加程序員的負擔。所以,為了增加方法的重用,就把這些能夠重用的方法抽象成類,以供程序員在其它地方可以調用。
當然了,這也是面向對象的一部分。其中的三層所指的就是:①視圖層(UI)②數據庫訪問層(DAL)③業務邏輯層(BLL)。當然了,還有所謂的第四層-實體層(model),這一層主要是在這三個層之間進行流動傳遞。但是為什么不叫四層架構。。。原因我也不知道,可能是因為實體層是外在的可以根據需要會隨時變化的(如:項目后續模塊的添加等)。而其它三個層,如果搭建完后,可以作為框架來使用的。。。
1)首先還是先來介紹一下實體層吧,就是我們通常所說的model
實體就是我們在開發項目過程中所要涉及的一些對象。把這些所要涉及的對象(如:新聞名稱,新聞上傳時間,供稿人,上傳文件的名稱等),都抽象成一個類。使用封裝字段方法,我們可以在視圖層通(主要是視圖層)過實例化對象的方法,來給我們的對象的屬性賦值。
簡單的看一段代碼吧,可能會能夠更加的清楚,明白
1 public class NewsModel 2 { 3 //新聞編號 4 private int nNewsId; 5 6 public int NNewsId 7 { 8 get { return nNewsId; } 9 set { nNewsId = value; } 10 } 11 12 //新聞名稱 13 private string strNewsName; 14 15 public string StrNewsName 16 { 17 get { return strNewsName; } 18 set { strNewsName = value; } 19 } 20 21 }
這里的NewsModel就是一個關於新聞的實體類,其中聲明了兩個private的屬性字段(一定要是private,防止非法賦值),使用public的構造函數,可以在外部給字段賦值。
下面的就是在視圖層來實例化對象,根據需要來給字段賦值,看下面的一段代碼:
NewsModel newModel = new NewsModel(); newModel.StrNewsName = this.TextBox1.Text;
當然了,這僅僅是一段代碼,其中並沒有給字段nNewsId賦值,因為我把它作為數據庫的id地段,已經設置成自動增長。這樣,就完成了視圖層對實體層的調用。
2)數據庫訪問層
數據庫庫訪問層,顧名思義,就是主要來完成對數據庫的訪問,等一系類的對數據庫操作的類。為什么要單獨的把對數據庫的操作抽象成一個單獨的類,我個人理解是因為在整個項目的開發過程中,不僅僅需要一次訪問數據庫,而是需要多次,如果每次都編寫數據庫訪問代碼的話,會增加程序員的個人工作量,而且對於代碼的易用性和簡潔性來說肯定是非常糟糕的。當然來可能還有其它的一些優點,我暫時還沒有發現。
既然是對數據庫的操作類,而且對數據庫的操作,無非就是四種:增刪改查。所以一個能提供增刪改查的通用類是必不可少的。這就是我們經常所說的,通用數據庫訪問類(很多的程序員都喜歡把這個類命名為SqlHelper,既然是名字,都是可以隨意起的,只要不違反C#語法命名規范,當然這樣命名也是有好處,就是可以使其他程序員根據類的名稱,大概判斷出這個類是要干什么的)。
當然了,我這次做自己項目的時候,所寫的數據庫訪問類就沒有我上次看周金橋老師的書,然后模仿寫的數據庫訪問類那么的復雜了(《【ASP.NET開發】ASP.NET對SQLServer的通用數據庫訪問類》)。當然了,我這里的數據庫訪問類,主要還是為了簡介,和易用,只要滿足我自己當前項目的需要就可以了,不是每做一個項目,都要寫一個功能全面的數據庫訪問類。
代碼如下,請大家參考,更喜歡哪個訪問類,自己可以根據自己口味,或者需要,直接用也可以:
/// <summary> ///創建一個SqlHelper的數據庫訪問通用類,完成對數據庫的所有操作 /// </summary> public class SqlHelper { //定義數據庫的連接字符串 private static readonly string connectionString = ConfigurationManager.ConnectionStrings["strConnectionString"].ConnectionString; /// <summary> /// 創建方法,完成對數據庫的非查詢的操作 /// </summary> /// <param name="sql">sql語句</param> /// <param name="parameters">傳入的參數</param> /// <returns></returns> public static int ExecuteNonQuery(string sql, params SqlParameter[] parameters) { using (SqlConnection con = new SqlConnection(connectionString)) { con.Open(); using (SqlCommand cmd = con.CreateCommand()) { cmd.CommandText = sql; cmd.Parameters.AddRange(parameters); string str = sql; return cmd.ExecuteNonQuery(); } } } /// <summary> /// 完成查詢的結果值 /// </summary> /// <param name="sql">sql語句</param> /// <param name="parameters">傳入的參數數組</param> /// <returns></returns> public static int ExecuteScalar(string sql, params SqlParameter[] parameters) { using (SqlConnection con = new SqlConnection(connectionString)) { con.Open(); using (SqlCommand cmd = con.CreateCommand()) { cmd.CommandText = sql; cmd.Parameters.AddRange(parameters); return Convert.ToInt32( cmd.ExecuteScalar()); } } } /// <summary> /// 主要執行查詢操作 /// </summary> /// <param name="sql">執行的sql語句</param> /// <param name="parameters">參數數組</param> /// <returns></returns> public static DataTable ExecuteDataTable(string sql, params SqlParameter[] parameters) { using (SqlConnection con = new SqlConnection(connectionString)) { con.Open(); using (SqlCommand cmd = con.CreateCommand()) { cmd.CommandText = sql; cmd.Parameters.AddRange(parameters); SqlDataAdapter adapter = new SqlDataAdapter(cmd); DataTable dt = new DataTable(); adapter.Fill(dt); return dt; } } } }
這樣的類創建好以后,其他的需要訪問數據庫的類,就可以根據自己的需要,完成相應的增刪改查的操作了。還是用一段代碼來演示吧:
/// <summary> ///NewsDALL 的摘要說明 /// </summary> public class NewsDALL { //向數據庫中插入新聞 public int AddNews(NewsModel model) { string sql = "insert into News (name,author,time,content,sort,isdelete) values(@name,@author,@time,@content,@sort,@isdelete)"; int nResult = SqlHelper.ExecuteNonQuery(sql, new SqlParameter("@name", model.StrNewsName), new SqlParameter("@author",model.StrNewsAuthor),new SqlParameter("@time", model.StrAddTime), new SqlParameter("@content", model.StrNewsContent), new SqlParameter("@sort", model.Sort), new SqlParameter("@isdelete", model.IsDelete1)); return nResult; } //執行數據庫的刪除操作 public int DeleteNew(int id) { string sql = "delete from News where id=@id"; int nResult = SqlHelper.ExecuteNonQuery(sql, new SqlParameter("@id", id)); return nResult; } //執行數據庫的更新操作 public int UpdateNew(NewsModel model, int nID) { string sql = "update News set name=@name,time=@time,content=@content where id=" + nID; int nResult = SqlHelper.ExecuteNonQuery(sql, new SqlParameter("@name", model.StrNewsName), new SqlParameter("@time", model.StrAddTime), new SqlParameter("@content", model.StrNewsContent)); return nResult; } //執行數據庫的查詢操作 public NewsModel GetNewsModel(int id)//聲明一次從數據庫中讀取新聞的條數 { string sql = "select * from News where id=@id"; DataTable dt = SqlHelper.ExecuteDataTable(sql, new SqlParameter("@id", id)); if (dt.Rows.Count <= 0) { return null; } else if (dt.Rows.Count == 1) { NewsModel newModel = new NewsModel(); DataRow dr = dt.Rows[0]; newModel.StrNewsName = dr["name"].ToString(); newModel.StrNewsAuthor = dr["author"].ToString(); newModel.StrAddTime = dr["time"].ToString(); newModel.StrNewsContent = dr["content"].ToString(); newModel.Sort = (int)dr["sort"]; return newModel; } else { throw new Exception("出現異常!"); } } }
這里的這個NewsDALL類,主要是來完成有關新聞需要對數據庫的各種操作,當然了,這只是這個類的一部分,主要是來演示NewsDALL類怎樣調用SqlHelper類中的方法,來完成對數據庫的操作的。
3)接下來就是最后一層,業務邏輯層了。
業務邏輯層的話主要來處理視圖層和數據庫訪問層之間的關系的。當然了,也可以直接在視圖層調用數據庫訪問層,但是對於關系來說可能會增加復雜性,所以前輩們就專門的抽象出來一個業務邏輯層,把所有的業務邏輯關系都在這一層處理清楚之后再,訪問數據庫訪問層,進行對數據的操作。(當然這是我自己的理解,如果有什么不對的話,請大家指正)
在我這次的項目中,貌似我的這一層完全是多余的,因為不需要什么太多的業務邏輯的處理,可以完全在視圖層直接訪問數據庫訪問層的。
還是使用代碼說話吧,當然這個仍然是NewsBLL類代碼的一部分:
/// <summary> ///業務邏輯層主要處理視圖層和數據庫訪問直接的關系 /// </summary> public class NewsBLL { //完成對數據庫的添加 public static int AddNew(NewsModel model) { NewsDALL newDALL = new NewsDALL(); return newDALL.AddNews(model); } //完成對數據的刪除 public static int DeleteNew(int i) { NewsDALL newDALL = new NewsDALL(); return newDALL.DeleteNew(i); } //返回一個新聞分類的對象 public static NewsModel GetModel(int intSort) { NewsModel model = new NewsModel(); if (intSort == 1) { model.StrNewSort1 = "學院新聞"; model.StrNewSort2 = ""; model.StrNewSort3 = ""; } else if (intSort == 2) { model.StrNewSort1 = "公告通知"; model.StrNewSort2 = ""; model.StrNewSort3 = ""; } .......... return model; } }
接下來就是在視圖層來通過訪問,業務邏輯層來和實體層,來玩成所需要的數據操作了。
還是使用代碼來描述吧,這個代碼主要來完成對數據進行添加:
public void InsertData() { NewsModel newModel = new NewsModel(); newModel.StrNewsName = this.TextBox1.Text; newModel.StrNewsAuthor = this.TxtBoxAuthor.Text; newModel.StrAddTime = this.TxtDate.Text; newModel.StrNewsContent = Server.HtmlDecode(FCKeditor1.Value); newModel.Sort =Convert.ToInt32( this.DropDownList2.SelectedValue.ToString()); //NewsBLL newBLL = new NewsBLL(); int nResult= NewsBLL.AddNew(newModel); if (nResult != 0) { Response.Write("<script>alert('添加成功!')</script>"); } else { Response.Write("<script>alert('添加失敗!')</script>"); } }
我以前自己做的圖,被大家指出了很多的錯誤。所以,我就引用了網絡上的一個圖片來解釋(如果侵害了您的版權,請您聯系我)
據我自己的理解,三層架構可以算是一個團隊項目開發的基本框架,在這個框架的基礎上可以滿足一些設計模式的需要。當然可以滿足模塊開發的需要。
總結:
對於我這次的開發項目來說,收獲還是很多的,以前僅僅是知道有三層架構這個東西,也看書,照着別人的代碼寫過,但是卻不能體會到這其中的真正意義。
優點:①使代碼的重用更加的高了,不需要像以前做項目,每次在一個頁面反復的編寫操作數據庫的代碼,而使用三層架構的話,只需要把注意力放在業務邏輯層 的業務邏輯的處理和數據庫訪問層的sql語句的編寫。
②代碼的整潔性,和易用性更加的高了。因為不同的操作都分別放在了不同的層,所以代碼邏輯更加清晰,如果做好注釋的話,別人能夠更加清楚的理解 編寫者的意圖。
③可擴展型更加的高了,根據需要在不同的層編寫代碼,然后調用就可以了。
④非常利於團隊開發。
當然了,三層架構的有點不僅僅有這些,不然也不會成為現在企業開發的基本框架,這只不過是我在開發中明顯的發現的優點,拿出來跟大家分享一下。
缺點:①就是性能上肯定比以前直接在相應的頁面編寫數據庫操作代碼上有點降低。但是這個完全是可以接受的,況且,對於我現在的水平就是代碼質量上可定還 有待提高,有更大的優化空間。
②就是在我的項目中,我覺得最大的浪費就是可以在視圖層直接訪問數據庫訪問層,因為要處理的業務邏輯實在是不多,所以還是有點代碼冗余吧。所以, 以后還是要跟據自己項目的需要,來靈活的使用,不一定要按照規定必須這樣做。
這僅僅是我的一點拙見,有什么地方錯誤,請大家積極指正。也歡迎大家跟我交流。