SoFunction
Updated on 2025-03-07

Detailed explanation of DataTable to Entity Instance in C#

Because Linq's query function is very powerful, I will convert the data obtained from the database into an entity collection List<T> for the convenience of processing.

The hard-coded method was started, which is easy to understand, but it is extremely versatile. Here is the code in the control table:

using System;
using ;
using ;
using ;
using ;
using ;
namespace Demo1
{
  class Program
  {
    static void Main(string[] args)
    {
      DataTable dt = Query();
      List&lt;Usr&gt; usrs = new List&lt;Usr&gt;();
      //Hard code is relatively efficient, but not flexible enough. If the entity changes, the code needs to be modified.      foreach (DataRow dr in )
      {
        Usr usr = new Usr { ID = &lt;Int32?&gt;("ID"), Name = &lt;String&gt;("Name") };
        (usr);
      }
      ();
    }
    /// &lt;summary&gt;
    /// Query data    /// &lt;/summary&gt;
    /// &lt;returns&gt;&lt;/returns&gt;
    private static DataTable Query()
    {
      DataTable dt = new DataTable();
      ("ID", typeof(Int32));
      ("Name", typeof(String));
      for (int i = 0; i &lt; 1000000; i++)
      {
        (new Object[] { i, ().ToString() });
      }
      return dt;
    }
  }
  class Usr
  {
    public Int32? ID { get; set; }
    public String Name { get; set; }
  }
}

Later, reflection is used to do this, and the attributes of the entity are assigned to the values, so that it can be common to all entities, and there is no need to modify the code after adding attributes.

The procedure is as follows:

static class EntityConvert
  {
    /// &lt;summary&gt;
    /// Convert DataTable to List<T>    /// &lt;/summary&gt;
    /// &lt;typeparam name="T"&gt;&lt;/typeparam&gt;
    /// &lt;param name="dt"&gt;&lt;/param&gt;
    /// &lt;returns&gt;&lt;/returns&gt;
    public static List&lt;T&gt; ToList&lt;T&gt;(this DataTable dt) where T : class, new()
    {
      List&lt;T&gt; colletion = new List&lt;T&gt;();
      PropertyInfo[] pInfos = typeof(T).GetProperties();
      foreach (DataRow dr in )
      {
        T t = new T();
        foreach (PropertyInfo pInfo in pInfos)
        {
          if (!) continue;
          (t, dr[]);
        }
        (t);
      }
      return colletion;
    }
  }

Add an extension method to make the program more general. But the efficiency is not very good, 1 million rows of data [only two columns], the conversion takes 2 seconds

Later I thought about using commission to do it. The commission prototype is as follows

Func<DataRow, Usr> func = dr => new Usr { ID = <Int32?>("ID"), Name = <String>("Name") };

The code is as follows:

static void Main(string[] args)
    {
      DataTable dt = Query();
      Func<DataRow, Usr> func = dr => new Usr { ID = <Int32?>("ID"), Name = <String>("Name") };
      List<Usr> usrs = new List<Usr>();
      Stopwatch sw = ();
      foreach (DataRow dr in )
      {
        Usr usr = func(dr);
        (usr);
      }
      ();
      ();
      ();
      ();
    }

The speed is indeed much faster. I tested it on my computer and it took 0.4 seconds. But the problem is again. This can only be used for the Usr class. We have to find a way to abstract this class into a generic T, which is both efficient in delegating and universal in generics.

The problem is that the above delegation is dynamically generated. After an afternoon of tossing, the method of dynamically generating the above delegation was finally developed. Mainly used dynamic Lambda expressions

public static class EntityConverter
  {
    /// &lt;summary&gt;
    /// DataTable generates entity    /// &lt;/summary&gt;
    /// &lt;typeparam name="T"&gt;&lt;/typeparam&gt;
    /// &lt;param name="dataTable"&gt;&lt;/param&gt;
    /// &lt;returns&gt;&lt;/returns&gt;
    public static List&lt;T&gt; ToList&lt;T&gt;(this DataTable dataTable) where T : class, new()
    {
      if (dataTable == null ||  &lt;= 0) throw new ArgumentNullException("dataTable", "The current object is null, cannot generate an expression tree");
      Func&lt;DataRow, T&gt; func = [0].ToExpression&lt;T&gt;();
      List&lt;T&gt; collection = new List&lt;T&gt;();
      foreach (DataRow dr in )
      {
        (func(dr));
      }
      return collection;
    }
    /// &lt;summary&gt;
    /// Generate expression    /// &lt;/summary&gt;
    /// &lt;typeparam name="T"&gt;&lt;/typeparam&gt;
    /// &lt;param name="dataRow"&gt;&lt;/param&gt;
    /// &lt;returns&gt;&lt;/returns&gt;
    public static Func&lt;DataRow, T&gt; ToExpression&lt;T&gt;(this DataRow dataRow) where T : class, new()
    {
      if (dataRow == null) throw new ArgumentNullException("dataRow", "The current object is null and cannot be converted to entity");
      ParameterExpression paramter = (typeof(DataRow), "dr");
      List&lt;MemberBinding&gt; binds = new List&lt;MemberBinding&gt;();
      for (int i = 0; i &lt; ; i++)
      {
        String colName = [i].ColumnName;
        PropertyInfo pInfo = typeof(T).GetProperty(colName);
        if (pInfo == null) continue;
        MethodInfo mInfo = typeof(DataRowExtensions).GetMethod("Field", new Type[] { typeof(DataRow), typeof(String) }).MakeGenericMethod();
        MethodCallExpression call = (mInfo, paramter, (colName, typeof(String)));
        MemberAssignment bind = (pInfo, call);
        (bind);
      }
      MemberInitExpression init = ((typeof(T)), ());
      return &lt;Func&lt;DataRow, T&gt;&gt;(init, paramter).Compile();
    }
  }

After testing, it takes 0.47 seconds to convert an entity under the same conditions using this method. In addition to using reflection to generate Lambda expressions for the first time, the expressions used for subsequent conversions are directly used.

The above is a detailed explanation of the DataTable conversion to entity examples in C# introduced by the editor. I hope it will be helpful to everyone. If you have any questions, please leave me a message and the editor will reply to everyone in time. Thank you very much for your support for my website!