首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

.NET 框架下輕量高效的 ORM 替代方案

     編輯:關於.NET

前言:從 Java 到 .NET 的 ORM 探索之路

從最初投身 Java 開發,到後來專注於 .NET 平台,經手過大大小小的專案不計其數。職業生涯初期,每完成一個程式都能獲得滿滿的成就感;但隨著開發年資增長、代碼行數激增,寫代碼逐漸從興趣變成了謀生工具。面對海量雷同的 SQL 語句,尤其是維護舊系統時對 SQL 的調試,更是讓人頭痛不已。於是,我一直致力於尋找一種方法,能夠擺脫重複編寫繁瑣 SQL 的命運。

Hibernate 的嘗試與局限

Java 平台上有成熟的 Hibernate ORM 框架,理應能解決這個問題。我迫不及待下載並用 MyEclipse 編寫測試程式,卻發現體驗遠不如預期。最大的阻礙在於那個 XML 配置文件:雖然借助 IDE 配置尚可接受,但一旦脫離 IDE,維護配置文件的困難程度絲毫不亞於直接維護 SQL 命令。當然,好處也是有的——至少不用逐條調試 SQL。雖然不太情願,但考慮到脫離 IDE 的情況較少,便「愛用不用」地用了一段時間。

轉向 .NET,決定自研 ORM 框架

隨後機緣巧合轉向 .NET 平台,從 .NET Framework 1.1 和 VS2003 起步,到 .NET Framework 2.0 和 VS2005,隨著開發經驗豐富、對 C# 特性理解深入,我終於決定親手打造一個更貼合 C# 風格的 ORM 框架:完全面向物件、更簡潔、更高效、對 IDE 智能感知支援更好(早期綁定)。

核心設計:以 EmployeeTable 為例

假設有一張員工表,欄位為 id、employee_id、name、department_id,對應實體類 EmployeeInfo。我們需要為這張表編寫資料存取類,提供增刪改查功能。以下是完整實現代碼:

public class EmployeeTable : TableAccess<EmployeeInfo> {
    internal override ColumnParameter[] FillColumnParameters(EmployeeInfo entity) {
        return base.BuildColumnParameter(
            entity.ID,
            entity.EmployeeID,
            entity.Name,
            entity.DepartmentID
        );
    }
    public override string TableName {
        get { return "employee_table"; }
    }
    public override TableColumnCollection TableColumns {
        get {
            TableColumnCollection list = new TableColumnCollection(4);
            list.AddRange(new TableColumn[] {
                new TableColumn("id", true), // 自增唯讀欄位
                new TableColumn("employee_id"),
                new TableColumn("name"),
                new TableColumn("department_id")
            });
            return list;
        }
    }
    internal override EmployeeInfo BuildEntity(MySqlDataReader reader, int startIndex) {
        EmployeeInfo info = new EmployeeInfo();
        info.ID = reader.GetInt32(0);
        info.EmployeeID = reader.GetString(1);
        info.Name = reader.GetString(2);
        info.DepartmentID = DataReadyUtility.GetInt32(reader, 3);
        return info;
    }
}

從代碼可見,針對單表存取,只需重寫抽象基類的 4 個方法,即可獲得以下功能:

  • 按主鍵獲取單筆資料 GetByPrimaryKey(object)
  • 獲取所有記錄 GetAll()
  • 條件查詢 Search(SearchConditionCollection, ...)
  • 分頁查詢 Search(SearchConditionCollection, int, int, ...)
  • 新增 Save(EmployeeInfo)
  • 按主鍵修改 Modify(...)
  • 按條件修改 Modify(SearchConditionCollection, ...)
  • 按主鍵刪除 Delete(...)
  • 按條件刪除 Delete(SearchConditionCollection, ...)

擴充業務邏輯方法

為了豐富功能,可對 EmployeeTable 進行擴充:

public class EmployeeTable : TableAccess<EmployeeInfo> {
    // 修改員工姓名
    public int ChangeName(int id, string name) {
        EmployeeInfo info = new EmployeeInfo();
        info.Name = name;
        // 僅修改指定欄位 TableColumns["name"]
        return base.Modify(id, info, ModifyBounds.None, TableColumns["name"]);
    }

    // 按姓名查詢(不分頁)
    public IList<EmployeeInfo> GetByName(string name) {
        SearchConditionCollection filter = new SearchConditionCollection();
        filter.Add(new SearchCondition("name", new ColumnComparison(SqlOperator.Like, name)));
        return base.Search(filter);
    }

    // 按姓名分頁查詢,輸出總筆數供前端分頁
    public IList<EmployeeInfo> GetByName(string name, int pageSize, int pageIndex, out int itemCount) {
        SearchConditionCollection filter = new SearchConditionCollection();
        filter.Add(new SearchCondition("name", new ColumnComparison(SqlOperator.Like, name)));
        return base.Search(filter, pageSize, pageIndex, out itemCount);
    }
}

實際調用範例

最後在業務邏輯層調用上述方法滿足專案需求:

public class EmployeeTableTest {
    void Test() {
        EmployeeTable employeeDAL = new EmployeeTable();
        SearchConditionCollection filter = new SearchConditionCollection();

        // 新增員工
        EmployeeInfo employee = new EmployeeInfo();
        employee.Name = "wfyfngu";
        employee.DepartmentID = 4;
        employeeDAL.Save(employee);

        // 主鍵查詢
        EmployeeInfo info = employeeDAL.GetByPrimaryKey(1);

        // 查詢所有
        IList<EmployeeInfo> all = employeeDAL.GetAll();

        // 分頁查詢
        int itemCount;
        IList<EmployeeInfo> pagedSource = employeeDAL.Search(null, 10, 1, out itemCount);

        // 修改姓名
        employeeDAL.ChangeName(1, "wfyfngu");

        // 刪除多筆(僅示範,實際應避免硬編碼欄位名)
        filter.Add(new SearchCondition("user_id", new ColumnComparison(SqlOperator.In, 1, 2, 5, 7)));
        employeeDAL.Delete(filter);

        // 模糊查詢 + 分頁
        filter.Clear();
        filter.Add(new SearchCondition("name", new ColumnComparison(SqlOperator.StartWith, "wfy")));
        IList<EmployeeInfo> result = employeeDAL.Search(filter, 10, 1, out itemCount);
    }
}

其他特性與原始碼說明

框架還支援簡單的聯表查詢、視圖查詢等功能。附件提供了針對 MySQL 編寫的 ORM 替代框架原始碼(因快取功能涉及另一類庫,附件中已移除,需自行加入)。主要類別包括:

  • ReadonlyTableAccess<T>
  • TableAccess<T>
  • JoinTableAccess<T>

這是一個輕量、高效、貼合 C# 開發習慣的 ORM 替代方案,歡迎有興趣的開發者參考學習。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved