一.前言
假設有這麼一個需求:從連接配接某個資料庫并從中查詢某個表的資訊,放到程式的位置進行存儲。
想必一開始的寫法會是下面這樣:
#region 根據資料庫添加内容
public void FillGridView(DataGridView MyGrid, string Upname, int Count)
{
//建立指令
SqlCommand com = new SqlCommand();
com.Connection = MyConnection;
com.CommandType = CommandType.Text;
//sql語句
com.CommandText = "select * from TAB_ACCESS where ACCESS_LEVEL=1 AND ACCESS_NAME='" + Upname + "'";
//執行語句
SqlDataReader reader = com.ExecuteReader();
string name = null;
string score = null;
//讀取資料
while (reader.Read())
{
name = reader["ACCESS_NAME"].ToString();
score = reader["ACCESS_SCORE"].ToString();
}
reader.Close();
//處理讀到的資料(實際業務)
int Sum = 0;
for (int j = 0; j < Count; j++)
{
Sum += RootCount[j];
if (RootCount[j] == 0)
Sum++;
}
if (RootCount[Count] > 0)
{
for (int i = 0; i < RootCount[Count]; i++)
{
MyGrid.Rows[Sum + i].Cells[0].Value = name;
MyGrid.Rows[Sum + i].Cells[1].Value = score;
}
}
else
{
MyGrid.Rows[Sum].Cells[0].Value = name;
MyGrid.Rows[Sum].Cells[1].Value = score;
}
}
#endregion
在這一個方法中,能完成業務的所有需求:連接配接資料庫,讀資料,處理資料。 程式能良好運作,沒有什麼問題。
這時,若需要擴充新的業務,或是在後期的運維中需要修改,那麼問題就出現了:方法中各自的邏輯都緊緊糾纏在一起,彼此間互相依賴,誰都是不可替換的。隻能寫新的方法,也就是重新完成連接配接資料庫,讀資料,處理資料的操作。這無疑加大了開發和維護的成本,效率很低。
本着 “高内聚,低耦合” 的思想,我們要想辦法降低各個業務的耦合性,連接配接資料庫歸連接配接資料庫,讀資料歸讀資料,處理資料歸處理資料,大家進水不犯河水。于是,在項目中,我們可以考慮采用分層式架構。
二.分層式架構
最常見的分層架構為(參考百度百科描述):
1.表示層(USL - User Show Layer)
位于最上層。用于顯示資料和接收使用者輸入的資料,為使用者提供一種互動式操作的界面。
2.業務邏輯層(Business Logic Layer)
業務邏輯層是系統架構中展現核心價值的部分。它的關注點主要集中在業務規則的制定、業務流程的實作等與業務需求有關的系統設計。
業務邏輯層在體系架構中的位置很關鍵,它處于資料通路層與表示層中間,起到了資料交換中承上啟下的作用。由于層是一種弱耦合結構,層與層之間的依賴是向下的,底層對于上層而言是“無知”的,改變上層的設計對于其調用的底層而言沒有任何影響。如果在分層設計時,遵循了面向接口設計的思想,那麼這種向下的依賴也應該是一種弱依賴關系。因而在不改變接口定義的前提下,理想的分層式架構,應該是一個支援可抽取、可替換的“抽屜”式架構。正因為如此,業務邏輯層的設計對于一個支援可擴充的架構尤為關鍵,因為它扮演了兩個不同的角色。對于資料通路層而言,它是調用者;對于表示層而言,它卻是被調用者。依賴與被依賴的關系都糾結在業務邏輯層上,如何實作依賴關系的解耦,則是除了實作業務邏輯之外留給設計師的任務。
3.資料層(DAL - Data Access Layer)
資料通路層:有時候也稱為是持久層,其功能主要是負責資料庫的通路,可以通路資料庫、二進制檔案、文本文檔或是XML文檔。簡單的說法就是實作對資料表的Select,Insert,Update,Delete的操作。
優點
1、開發人員可以隻關注整個結構中的其中某一層;
2、可以很容易的用新的實作來替換原有層次的實作;
3、可以降低層與層之間的依賴;
4、有利于标準化;
5、利于各層邏輯的複用。
6、結構更加的明确
7、在後期維護的時候,極大地降低了維護成本和維護時間
缺點
1、降低了系統的性能。這是不言而喻的。如果不采用分層式結構,很多業務可以直接造訪資料庫,以此擷取相應的資料,如今卻必須通過中間層來完成。
2、有時會導緻級聯的修改。這種修改尤其展現在自上而下的方向。如果在表示層中需要增加一個功能,為保證其設計符合分層式結構,可能需要在相應的業務邏輯層和資料通路層中都增加相應的代碼。
3、增加了開發成本。
三.執行個體解析
拿最近做的資料庫項目的架構來講,初步的分層架構如下:
在實際應用中的表現是這樣的:
Interface 為接口層。在此定義資料庫通路接口。
DataModel 為資料模型層。在此定義各種類和結構體用于存儲資料(在架構中可以去掉)。
DAL為資料通路層。資料庫的連接配接以及所有對資料庫的增删改查都在此實作。
BLL為業務邏輯層。讀到的資料在這裡進行處理,比如将存儲到某個結構體或類中。
簡單舉例
假設資料庫中存在一個部門表(TAB_DEPART) , 我們需要從中查詢所有記錄,存到預先定義好的List<DepartmentRecord>中。
操作流程如下圖:
Interface定義:
namespace BSH_DBA.Interface
{
/// <summary>
/// UserDAL接口
/// </summary>
public interface IUserDAL
{
/// <summary>
/// 查詢所有部門記錄
/// </summary>
/// <param name="conn">連接配接字段</param>
/// <returns>DataTable:成功;其他:失敗</returns>
DataTable SelectDepartment(string conn);
}
}
DAL中繼承接口并寫詳細資料庫操作:
namespace BSH_DBA.DAL
{
/// <summary>
/// 使用者管理子產品庫資料操作
/// </summary>
public class UserDAL : IUserDAL
{
/// <summary>
/// 查詢所有部門記錄
/// </summary>
/// <param name="conn">連接配接字段</param>
/// <returns>DataTable:成功;其他:失敗</returns>
public DataTable SelectDepartment(string conn)
{
StringBuilder MysqlCommand = new StringBuilder();
try
{
MysqlCommand.Append(string.Format(@"select * from {0}", NamedConfig.TAB_DEPART));
DataTable dt = MySqlHelper.ExecuteDataset(conn, CommandType.Text, MysqlCommand.ToString()).Tables[0];
return dt;
}
catch (Exception ex)
{
Trace.TraceError(ex.ToString());
return null;
}
}
}
BAL中調用接口讀到資料并存儲:
namespace BSH_DBA.BLL
{
/// <summary>
/// 使用者業務
/// 注:使用者包括服務人員、管理者、超級管理者、Admin
/// </summary>
public class UserBLL
{
private static readonly IUserDAL iUser = new UserDAL();
/// <summary>
/// 查詢所有部門記錄
/// </summary>
/// <param name="conn">連接配接字段</param>
/// <param name="list_record">輸出:部門清單</param>
/// <returns>0:成功;其他:失敗</returns>
public static int SelectDepartment(string conn, List<DepartmentRecord> list_record)
{
//調用接口,讀取資料
DataTable dt = iUser.SelectDepartment(conn);
if(dt == null)
{
return 1;
}
//周遊DataTable,将裡面資料存到List中
foreach(DataRow dr in dt.Rows)
{
string id = dr["depart_id"].ToString();
string name = dr["depart_name"].ToString();
string upid = dr["depart_upid"].ToString();
DepartmentRecord drecord = new DepartmentRecord(id,name,upid);
list_record.Add(drecord);
}
return 0;
}
}
}
以上便是以分層架構完成的資料庫業務操作。供參考。