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

DataRow 轉實體通用映射器:反射實現 DataTable 到 POCO 零代碼映射

     編輯:關於ASP.NET

ORM 核心環節:將 DataRow/DataTable 映射為強型別實體。本文提供基於反射的通用 Mapper 類,支援單行 ToEntity 與批次 ToList,處理型別轉換、DBNull、日期解析等細節。

核心 Mapper 實現

public static class Mapper {
    // 單行映射:非泛型
    public static object ToEntity(DataRow row, Type entityType) {
        if (entityType == null || row == null) return null;
        var entity = Activator.CreateInstance(entityType);
        CopyToEntity(entity, row);
        return entity;
    }

    // 單行映射:泛型
    public static T ToEntity<T>(DataRow row) where T : new() {
        if (row == null) return new T();
        var item = new T();
        CopyToEntity(item, row);
        return item;
    }

    // 核心複製邏輯
    public static void CopyToEntity(object entity, DataRow row) {
        if (entity == null || row == null) return;
        var props = entity.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
        foreach (var prop in props) {
            if (!CanSet(prop, row)) continue;
            try {
                var val = row[prop.Name];
                if (val is DBNull) { prop.SetValue(entity, null); continue; }
                SetValue(entity, row, prop);
            } catch { /* 記錄日誌,跳過單屬性失敗 */ }
        }
    }

    private static bool CanSet(PropertyInfo prop, DataRow row) 
        => prop.CanWrite && row.Table.Columns.Contains(prop.Name);

    private static void SetValue(object entity, DataRow row, PropertyInfo prop) {
        var raw = row[prop.Name];
        var targetType = prop.PropertyType;
        // 處理 Nullable<DateTime> 與 DateTime
        if (targetType == typeof(DateTime) || targetType == typeof(DateTime?)) {
            if (DateTime.TryParse(raw.ToString(), out var dt))
                prop.SetValue(entity, dt);
            return;
        }
        // 可擴展:Guid、Enum、自定義 TypeConverter
        prop.SetValue(entity, Convert.ChangeType(raw, targetType));
    }
}

批次轉換擴展

public static List<T> ToList<T>(DataTable table) where T : new() {
    var list = new List<T>();
    if (table == null) return list;
    foreach (DataRow row in table.Rows)
        list.Add(ToEntity<T>(row));
    return list;
}

// 進階:支援欄位名與屬性名不一致(Attribute 映射)
[AttributeUsage(AttributeTargets.Property)]
public class ColumnAttribute : Attribute { public string Name { get; set; } }

// 修改 CanSet/GetColumnName 邏輯讀取 Attribute

效能優化關鍵點

問題方案效果
反射每行調用 GetProperties()靜態緩存 PropertyInfo[] 按型別減少 90%+ 反射開銷
SetValue 裝箱/拆箱發動委派/Expression Tree 編譯 Setter接近手寫代碼速度
DBNull 檢查分散統一在 Convert.ChangeType 前處理代碼簡潔、邏輯集中
日期格式文化差異指定 CultureInfo.InvariantCulture跨伺服器穩定

生產級替代方案

  • Dapper:connection.Query<T>(sql) 內建高效映射(IL 生成)。
  • AutoMapper:Mapper.Map<T>(row) 支援複雜映射規則、Profile 管理。
  • FastMember:ObjectReader 以委派高速讀寫成員。
  • 手寫映射:極致效能場景(百萬行/秒),代碼生成工具 (T4/Source Generator) 產出。

單元測試要點

  • 欄位缺失、型別不匹配、DBNull、日期格式、Nullable 型別、巢狀物件、循環引用。
  • 效能基準測試:10 萬行轉換耗時、記憶體分配、GC 壓力。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved