技術圖文:如何實現 DataTable 與模型類 List 的相互轉換?

通常情況下,我們在做工程項目的時候,需要把待處理的數據存儲在數據庫中。

通過 SQLSelect 語句很容易把查詢的結果以 DataTable 的方式得到,但在對 DateTable 中的數據進行進一步的檢索時遠遠沒有模型類 List<T> 方便。 所以,在做工程項目時,會把查詢到的 DataTable 轉化成模型類 List<T>, 處理完畢後如果有所改動則把這個模型類 換回成 DataTable 以便完成數據庫中的相應改動。

上週在做一個電力局項目時對導入的上萬條數據進行插入操作就是這樣做的,參見一下圖文:


技術分析

如何實現 DataTableList<T> 的相互轉化呢?

這裏需要掌握 C# 中的 泛型 以及 反射 的基礎知識

泛型部分:

反射部分:

通過泛型,我們可以把任何一個模型類 List<T> 轉化成 DataTable,也可以把任何一個 DataTable 轉化成對應的 List<T>,只要這裏 T 類型的 public 屬性DataTableColumnName 對應即可。當然屬性的獲取是通過反射技術完成的。

有關泛型和反射的知識,可以查看上面的圖文,我在這裏就不在重複了。


代碼實現

下面,通過一個實際項目的例子來說明相互轉換的代碼與具體的應用。

Step1. 設備臺賬的結構 AcountItem

/// <summary>
/// 臺賬Item
/// </summary>
public class AccountItem
{
    /// <summary>
    /// 設備ID
    /// </summary>
    public string EquipmentId
    {
        get;
        set; 
    }
    /// <summary>
    /// 廠站名稱
    /// </summary>
    public string FactoryStationName
    {
        get;
        set; 
    }
    /// <summary>
    /// 廠站類型
    /// </summary>
    public string FactoryStationType
    {
        get;
        set; 
    }
    /// <summary>
    /// 一次設備名稱
    /// </summary>
    public string PrimaryDeviceName 
    { get; set; }
    /// <summary>
    /// 一次設備電壓等級
    /// </summary>
    public string PrimaryDeviceVoltageLevel 
    { get; set; }
    /// <summary>
    /// 製造廠家
    /// </summary>
    public string Manufacturer 
    { 
        get;
        set; 
    }
    /// <summary>
    /// 保護類別
    /// </summary>
    public string ProtectionCategory 
    {
        get;
        set;   
    }
    /// <summary>
    /// 保護型號
    /// </summary>
    public string ProtectionType 
    {
        get;
        set; 
    }
    /// <summary>
    /// 軟件版本
    /// </summary>
    public string SoftwareVersion 
    { 
        get;
        set; 
    }
    /// <summary>
    /// 保護名稱
    /// </summary>
    public string ProtectionName 
    {
        get;
        set; 
    }
    /// <summary>
    /// 投運日期
    /// </summary>
    public string CommissionDate 
    {
        get;
        set; 
    }
    /// <summary>
    /// 出廠日期
    /// </summary>
    public string ProductionDate 
    {
        get;
        set; 
    }
    /// <summary>
    /// 所在屏櫃
    /// </summary>
    public string ScreenCabinets 
    {
        get;
        set; 
    }
    /// <summary>
    /// 保護套別
    /// </summary>
    public string ProtectiveSleeve 
    {
        get;
        set; 
    }
}

Step2. 把模型類 List<T> 轉化爲 DataTable

public static DataTable ListToDataTable<T>(IEnumerable<T> collection)
{
    if (collection == null)
        throw new ArgumentNullException();

    PropertyInfo[] props = typeof (T).GetProperties();
    DataTable dt = new DataTable();
    dt.Columns.AddRange(props.Select(
            p => new DataColumn(p.Name, p.PropertyType)
        ).ToArray());
    if (collection.Any())
    {
        for (int i = 0; i < collection.Count(); i++)
        {
            ArrayList tempList = new ArrayList();
            foreach (PropertyInfo pi in props)
            {
                object obj = pi.GetValue(collection.ElementAt(i), null);
                tempList.Add(obj);
            }
            object[] array = tempList.ToArray();
            dt.LoadDataRow(array, true);
        }
    }
    return dt;
}

Step3. 舉例,把 List<AcountItem> 轉化爲 DataTable

// 初始化鏈表並加入數據。
List<AccountItem> lst = new List<AccountItem>(); 

DataTable dt = ListToDataTable(lst);

dt 數據表列集合的列名依次爲:

  • EquipmentId
  • FactoryStationName
  • FactoryStationType
  • PrimaryDeviceName
  • PrimaryDeviceVoltageLevel
  • Manufacturer
  • ProtectionCategory
  • ProtectionType
  • SoftwareVersion
  • ProtectionName
  • CommissionDate
  • ProductionDate
  • ScreenCabinets
  • ProtectiveSleeve;

Step4. DataTable 轉化爲 List

public static List<T> DataTableToList<T>(DataTable dt) where T : new()
{
    List<T> result = new List<T>();
    foreach (DataRow dr in dt.Rows)
    {
        T item = new T();
        PropertyInfo[] props = item.GetType().GetProperties();
        foreach (PropertyInfo pi in props)
        {
            string tempName = pi.Name;
            if (dt.Columns.Contains(tempName))
            {
                if (pi.CanWrite == false)
                    continue;

                object value = dr[tempName];
                if (value != DBNull.Value)
                    pi.SetValue(item, value, null);
            }
        }
        result.Add(item);
    }
    return result;
}

Step5. 舉例,把 Step3 得到的 DataTable 轉化爲 List<AccountItem>

List<AccountItem> lst = DataTableToList(dt);

通過調用 Step4 帶約束的泛型方法,可以得到模型類 List<AccountItem>


總結

到此爲止,DataTableList<T> 的相互轉換就介紹完了,由於整個項目都是利用 List<T> 來構建邏輯的,所以整個系統可以具有良好的結構,通過 LINQ 也能滿足效率的要求。今天就到這裏吧!See You!


相關圖文

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章