2013-06-02 66 views
1

我正在使用oracle作爲後端的asp.net項目。 Initialy我使用三層架構開發此應用程序,其中UI爲aspx頁面,BLL和DAL爲類庫項目。我在BLL和DAL中都使用了靜態類和方法。 DAL僅由具有接受由BLL類轉發的查詢的Select,Execute和ExecuteScalar靜態方法的單個類組成。在三層體系結構中正確的功能佈局

DAL

private static string connString = "" 

private static OracleConnection conn; 

public static OracleConnection OpenConn() 
{ 
    if (conn==null) 
    { 
    conn = new OracleConnection(connString); 
    } 

    if (conn.State != ConnectionState.Open) 
    { 
    conn.Open(); 
    } 

    return conn; 
} 

public static DataTable Select(string query) 
{ 
    DataTable dt = new DataTable(); 
    OracleDataAdapter da = new OracleDataAdapter(query, OpenConn()); 
    da.Fill(dt); 
    return dt; 
} 

public static void Execute(string query) 
{ 
    OracleCommand cmd = new OracleCommand(query, OpenConn()); 
    cmd.ExecuteNonQuery(); 
} 

public static int ExecuteScaler(string query) 
{ 
    OracleCommand cmd = new OracleCommand(query, OpenConn()); 
    int id = Convert.ToInt32(cmd.ExecuteScalar()); 
    return id; 
} 

這個DAL由BLL類調用的方法是如下 員工BLL

public static DataTable GetEmployees(int facilityid) 
    { 
     DataTable dt = new DataTable(); 
     string q = string.Format("SELECT * FROM .."); 
     dt = OraDAL.Select(q); 
     return dt; 
    } 


    public static DataTable AddEmployee(string name, , int departmentid , int employeeType) 
    { 
     DataTable dt = new DataTable(); 
     string q = string.Format("INSERT INTO ..."); 
     dt = OraDAL.Select(q); 
     return dt; 
    } 

現在我重構應用。與BLL和DAL相同的三層體系結構與類庫項目一樣,具有名爲Domain的其他類庫項目,以包含所有其他項目引用的域類。我使用這些類來進行圖層之間的數據傳輸。這次將DAL類保持爲靜態,並將BLL保留爲正常類。我已將大部分功能(查詢)移至DAL。現在DAL具有類EmployeesDAL,DepartmentsDAL以及包含Select,Execute和ExecuteScalar靜態方法的泛型類。

Employee.cs

public class Employee 
{ 
    public int Id { get; set; } 

    public string Name { get; set; } 

    public Department department { get; set; } 

    public EmployeeType employeeType { get; set; } 
} 

EmployeesDAL

public static List<Employee> GetEmployees(int departmentid) 
    { 
     if (departmentid > 0) 
     { 
      string query = string.Format("SELECT * FROM EMPLOYEES WHERE department='{0}')", departmentid); 
      return GetCollection(OraDAL.Select(query)); 
     } 

     return null; 
    } 

    public static Employee GetEmployee(int employeeid) 
    { 
     if (employeeid > 0) 
     { 
      string query = string.Format("SELECT * FROM PMS_EMPLOYEES WHERE Id='{0}'", employeeid); 
      return GetSingle(OraDAL.Select(query)); 
     } 

     throw new Exception("Employee id not valid"); 
    } 

    public static int AddEmployee(Employee employee) 
    { 
     if (employee != null) 
     { 
      string query = string.Format("INSERT INTO PMS_EMPLOYEES (name, department, employee_type) VALUES ('{0}','{1}','{2}')", employee.Name, employee.department.Id, employee.employeeType.Id); 
      return OraDAL.Execute(query); 
     } 

     throw new Exception("Values not valid"); 
    } 

private static List<Employee> GetCollection(DataTable table) 
    { 
     List<Employee> employees = null; 
     if (table != null) 
     { 
      if (table.Rows.Count > 0) 
      { 
       employees = new List<Employee>(); 
       foreach (DataRow row in table.Rows) 
       { 
        employees.Add(ReadDataRow(row)); 
       } 
      } 
     } 
     return employees; 
    } 

    private static Employee GetSingle(DataTable table) 
    { 
     if (table != null) 
     { 
      if (table.Rows.Count > 0) 
      { 
       DataRow row = table.Rows[0]; 
       return ReadDataRow(row); 
      } 
     } 

     return null; 
    } 

    private static Employee ReadDataRow(DataRow row) 
    { 
     Employee employee = new Employee() 
     { 
      Id=int.Parse(row["ID"].ToString()), 
      Name=row["NAME"].ToString(), 
      employeeType=EmployeeTypesDAL.GetEmployeeType(int.Parse(row["EMPLOYEE_TYPE"].ToString())), 
      department=DepartmentsDAL.GetDepartment(int.Parse(row["DEPARTMENT"].ToString())) 
     }; 

     return employee; 
    } 

EmployeesBLL.cs

public class EmployeesBLL 
{ 
    public List<Employee> GetEmployees(int departmentid) 
    { 
     if (departmentid > 0) 
     { 
      return EmployeesDAL.GetEmployees(departmentid); 
     } 

     return null; 
    } 

    public int AddEmployee(Employee employee) 
    { 
     if (employee != null) 
     { 
      return EmployeesDAL.AddEmployee(employee); 
     } 

     throw new Exception("Employee cannot be null"); 
    } 

的職位是時間越來越長,但我希望你能更好地瞭解這種情況。 我面對新設計的幾個問題,並讓我問這個問題,這是做事的正確方法嗎?由於主要目標是避免在不同層之間來回移動數據表。雖然這種編碼邏輯的新方法太耗時,但值得付出努力。業務層越來越薄,因爲看起來他們提供的唯一服務就是調用DAL的類似方法,我首先需要BLL嗎?如果是,在需要單獨的BLL的情況下可能出現什麼情況。

編輯,我和上面的設計注意

一個問題是數據庫調用的次數。調用次數太多,因爲當填充對象時,所有子對象也都被填充,導致調用數據庫。例如填充Employee對象將導致填充部門實例。在大多數情況下,我只需要部門識別碼而不是整個部門信息。

+1

你的設計是數據驅動設計的一個很好的例子,是的 - 在它的業務邏輯只是一個封裝在crud操作。如果你的應用程序只能做到這一點,那真的很好。順便說一下,如果您打算對BL承擔更多責任,請考慮O/RM方法,否則您會花費太多時間來支持您的數據訪問層代碼庫。 – mikalai

回答

1

3層架構的部分的目的如下:

1. UI

允許用戶與域模型

2交互。Domain Model/Middle Tier

將特定域或業務流程的翻譯包含到代碼中。作爲您特定業務問題或環境的代表。該層應包含應用程序的所有業務規則和業務對象。

3.數據訪問層

允許域模型對象持久保存到和從數據存儲中檢索。數據訪問層僅從持久性數據存儲(即數據庫)中獲取數據,並將其轉換爲域模型對象,並將域模型對象存儲並保存到數據存儲中。

在這三個方面,我認爲最重要的領域是領域模型/中間層。這是應用程序的核心和靈魂,是應用程序真正解決特定業務問題的地方,併爲將使用您的軟件的組織提供價值。其他兩個領域的目的僅僅是將您的領域模型展示給用戶(UI)或者允許它被檢索或存儲(數據層)。

這意味着你應該努力盡可能地在域模型/中間層上工作。這是您解決組織的特定業務問題的地方,也是您可以爲公司或客戶真正增加價值的地方。

在將這個通用原則應用於您的特定情況時,我有以下意見/建議。

  1. 您正在手動創建數據訪問層並手工製作SQL語句。一般來說,這是一個非常低價值的使用你的時間。有許多object-relation mapper(ORM)工具,例如nHibernateentity framework,它們將負責從數據存儲區加載域模型對象所需的低級管道工具,並堅持將這些對象保留回數據存儲區。我想你可能想要調查這些。我認爲使用這些ORM工具之一的解決方案將比您提出的任一選項更好。

  2. 根據您發佈的代碼,您的域模型/中間層只是一個屬性包,沒有業務邏輯或業務規則。如果確實如此,那麼這就是它應該是的。但是,與您的利益相關者進行交流並且真正努力在域模型中對其流程進行建模將會很有用,因爲這是您最能爲組織增值的地方。

我知道這有點長,但希望對你有幫助。

+0

謝謝joe ..我已經使用了EF,但是當我嘗試將它與oracle一起使用時,我遇到了一些問題。由於我沒有完全理解EF並且在不同的論壇上閱讀過ORM有自己的問題,所以我採用了這種方法。我想知道在網上有沒有好的項目源代碼,他們使用的是域對象,但沒有使用ORM,因此絕對不能使用ORM。 – ZedBee

+1

完成了兩件事情(手工製作DAL vs.使用ORM)我個人發現ORM是一個巨大的節省時間的工具,通過快速處理低級管道並讓我在中間層上花費更多時間來節省我的痛苦,這對我來說是最有價值的公司。我已經使用nHibernate很多,我認爲它與oracle很好。但是,ORM肯定有學習曲線,需要一些時間才能熟練掌握它們。另外,正如你指出的那樣,還有其他選擇。 –

+0

謝謝..我一定會嘗試nHibernate ..但我仍然想看看如何在不使用ORM的情況下以一種漂亮而整潔的方式完成。我希望找到任何這樣的開源項目 – ZedBee

1

表示層

你已經知道這一點。這是你的用戶界面。它由視圖,視圖模型和(控制器/演示者)組成。此表示層只具有與UI(定位,css樣式等)相關的邏輯。它不知道BLL的實現(只是接口),並且根本不知道DAL(存儲)。

業務層

如果你的業務邏輯所在。每個選擇操作,計算,驗證,插入操作,刪除,更新操作都屬於這裏。它不知道用戶界面,所以它可以在任何用戶界面中工作,無論是web /桌面/移動應用程序,還是相同的業務邏輯。這意味着在這一層,沒有使用明顯的緩存/會話。相反,你可以把它包裝在一些界面中。它不知道存儲,這意味着你需要另一層來做存儲,而它是DAL

數據訪問層

這一層簡單地做CRUD操作與存儲(平面文件,數據庫,Web服務,XML,JSON等),並返回對象模型。就這樣。它不知道用戶界面和業務規則。這一層的目的是爲了便於更換。假設您需要將數據庫中的存儲替換爲xml,這是該層的工作,而不改變其他層。

回答你的問題

希望你已經知道了3層的目的。

現在,假設你在你的情況下,使用3層與BLL:

  1. 爲Employee存儲不影響BLL和UI
  2. 業務邏輯(新的搜索參數)的任何變化的任何變化確實會影響DAL
  3. 您BLL不知道數據訪問(連接/ DB背景等),意味着它並不需要知道BLL
在所有
  • 其他明顯的映射連接

    現在,假設你使用2層沒有BLL你的情況:

    1. 到員工存儲的任何更改不影響UI(無BLL)
    2. 任何更改業務邏輯(新的搜索參數)不影響DAL
    3. 您的用戶界面知道DAL。如果您將其設計爲分離項目,則會添加引用並打破分層。這爲您的用戶界面直接訪問其他DAL提供了機會。

    是的,在你的情況下使用BLL是沒有用的,因爲你只能分開你的UI和DAL。但是,這是3層的關鍵是不是?

    也就是說,如果你正在使用存儲過程select。您真正需要的是DAL中的通用存儲庫模式,它將在BLL訪問期間幫助您。

  • +0

    謝謝Fendy ..你談論業務層的驗證,但我正在做的是驗證背後的代碼(UI)的輸入,因爲目標是UI應該發送整齊的對象(例如,員工對象)到buisiness層進行進一步操作。我所說的是,雖然每層都有某種形式的驗證,但不是主要驗證的UI,因爲這是捕獲用戶提供的數據的入口點。在從這些數據中構造對象之前驗證此層的用戶輸入是否更好? – ZedBee

    +1

    如果談論數據類型(int等),那麼是的。無論如何,您都會將模型對象傳遞給業務邏輯。我在BLL中討論的是業務邏輯驗證,例如:金錢不得低於0,年齡必須高於17,名字長度必須低於32等等。畢竟,如果您想在UI級別複製驗證,那麼沒關係,但如果它需要的業務角色,將其添加到BLL – Fendy

    +0

    謝謝..這是有道理的..我同意業務規則應在BLL驗證。 – ZedBee