问题根源:现在编码已经习惯了面向对象编码,数据库访问层也由ORM代替了ADO,DataTable一般用的越来越少,可是一些公用方法还是用到DataTable了,理由其实很简单就是公用方法里不用DataTable就得用反射访问实体集合,反射的访问效率比DataTable低很多是毋庸置疑的。可是我还是觉得很苦恼,心中有两个疑问:
1、访问实体集合到底比访问DataTable慢多少呢?
2、后台数据层提供的是实体集合,调用公用方法势必要转为DataTable,那转换耗时多少呢?
接下来我新建了一个控制台程序,简单写了一个实体对象:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class TestEntity 2 { 3 public string Col1 { get; set; } 4 public string Col2 { get; set; } 5 public string Col3 { get; set; } 6 public string Col4 { get; set; } 7 public string Col5 { get; set; } 8 public string Col6 { get; set; } 9 public string Col7 { get; set; } 10 public string Col8 { get; set; } 11 public string Col9 { get; set; } 12 public string Col10 { get; set; } 13 public string Col11 { get; set; } 14 public string Col12 { get; set; } 15 public string Col13 { get; set; } 16 public string Col14 { get; set; } 17 public string Col15 { get; set; } 18 public string Col16 { get; set; } 19 public string Col17 { get; set; } 20 public string Col18 { get; set; } 21 public string Col19 { get; set; } 22 public string Col20 { get; set; } 23 public string Col21 { get; set; } 24 public string Col22 { get; set; } 25 public string Col23 { get; set; } 26 public string Col24 { get; set; } 27 public string Col25 { get; set; } 28 public string Col26 { get; set; } 29 public string Col27 { get; set; } 30 public string Col28 { get; set; } 31 public string Col29 { get; set; } 32 public string Col30 { get; set; } 33 }
然后写了一个创建实体集合的方法:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 private static IList<TestEntity> CreateList(long count) 2 { 3 var result = new List<TestEntity>(); 4 5 for (var i = 0; i < count; i++) 6 { 7 var entity = new TestEntity(); 8 var propertys = typeof(TestEntity).GetProperties(); 9 foreach (var p in propertys) 10 { 11 p.SetValue(entity, i.ToString()); 12 } 13 result.Add(entity); 14 } 15 16 return result; 17 }
然后写了一个创建DataTable的方法:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 private static DataTable CreateTable(long count) 2 { 3 var result = new DataTable(); 4 5 for (var i = 1; i <= 30; i++) 6 { 7 result.Columns.Add(new DataColumn("Col" + i.ToString(), Type.GetType("System.String"))); 8 } 9 10 for (var i = 0; i < count; i++) 11 { 12 var row = result.NewRow(); 13 for (var j = 1; j <= 30; j++) 14 { 15 row["Col" + j.ToString()] = i; 16 } 17 result.Rows.Add(row); 18 } 19 20 return result; 21 }
准备工作做好了,现在写了两个读取的方法:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 private static void ReadEntity<T>(IList<T> list) 2 { 3 for (var i = 0; i < list.Count; i++) 4 { 5 var entity = list[i]; 6 var propertys = typeof(T).GetProperties(); 7 for (var j = 0; j < propertys.Count(); j++) 8 { 9 var value = ""; 10 value += propertys[j].GetValue(entity).ToString(); 11 } 12 } 13 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 private static void ReadDataTable(DataTable data) 2 { 3 for (var i = 0; i < data.Rows.Count; i++) 4 { 5 for (var j = 0; j < data.Columns.Count; j++) 6 { 7 var value = ""; 8 value += data.Rows[i][j].ToString(); 9 } 10 } 11 }
记录一下耗时,通过控制台打印出来:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 static void Main(string[] args) 2 { 3 for (var i = 0; i < 10; i++) 4 { 5 var count = Convert.ToInt64(Console.ReadLine()); 6 if (count == 0) break; 7 8 var list = CreateList(count); 9 10 11 DateTime start = DateTime.Now; 12 var table = CreateTable(count); 13 DateTime end = DateTime.Now; 14 15 var tick0 = (end - start).Ticks; 16 17 start = DateTime.Now; 18 ReadDataTable(table); 19 end = DateTime.Now; 20 21 var tick1 = (end - start).Ticks; 22 23 start = DateTime.Now; 24 ReadEntity(list); 25 end = DateTime.Now; 26 27 var tick2 = (end - start).Ticks; 28 29 Console.WriteLine("DataTable:条数" + count + "耗时" + tick1.ToString()); 30 Console.WriteLine("反射读取Entity:条数" + count + "耗时" + tick2.ToString()); 31 } 32 }
运行程序,输入行数,显示结果如下:
可以看出反射读取耗时与DataTable读取耗时相比2到4倍。
这时你肯定会想差这么多,看来公用方法使用DataTable是没错了。
但是,开头咱们提到的两个疑问,第一个疑问解决了,但是第二个疑问呢,转换耗时多少呢?
现在我把第二个疑问拆解了一下,转换需要进行的是,创建DataTable,遍历读取实体集合(注意一下这个不是反射),这样我就写了一个方法:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 private static DataTable CreateTable(IList<TestEntity> list) 2 { 3 var result = new DataTable(); 4 5 for (var i = 1; i <= 30; i++) 6 { 7 result.Columns.Add(new DataColumn("Col" + i.ToString(), Type.GetType("System.String"))); 8 } 9 10 for (var i = 0; i < list.Count; i++) 11 { 12 var row = result.NewRow(); 13 row["Col1"] = list[i].Col1; 14 row["Col2"] = list[i].Col2; 15 row["Col3"] = list[i].Col3; 16 row["Col4"] = list[i].Col4; 17 row["Col5"] = list[i].Col5; 18 row["Col6"] = list[i].Col6; 19 row["Col7"] = list[i].Col7; 20 row["Col8"] = list[i].Col8; 21 row["Col9"] = list[i].Col9; 22 row["Col10"] = list[i].Col10; 23 row["Col11"] = list[i].Col11; 24 row["Col12"] = list[i].Col12; 25 row["Col13"] = list[i].Col13; 26 row["Col14"] = list[i].Col14; 27 row["Col15"] = list[i].Col15; 28 row["Col16"] = list[i].Col16; 29 row["Col17"] = list[i].Col17; 30 row["Col18"] = list[i].Col18; 31 row["Col19"] = list[i].Col19; 32 row["Col20"] = list[i].Col20; 33 row["Col21"] = list[i].Col21; 34 row["Col22"] = list[i].Col22; 35 row["Col23"] = list[i].Col23; 36 row["Col24"] = list[i].Col24; 37 row["Col25"] = list[i].Col25; 38 row["Col26"] = list[i].Col26; 39 row["Col27"] = list[i].Col27; 40 row["Col28"] = list[i].Col28; 41 row["Col29"] = list[i].Col29; 42 row["Col30"] = list[i].Col30; 43 result.Rows.Add(row); 44 } 45 46 return result; 47 }
在主函数增加时间记录:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 start = DateTime.Now; 2 CreateTable(list); 3 end = DateTime.Now; 4 5 var tick3 = (end - start).Ticks; 6 Console.WriteLine("Entity:条数" + count + "耗时" + tick3.ToString());
执行结果如下:
创建DataTable加上读取与通过反射直接读取实体集合,耗时相差不是很明显了,起码不是倍率级的了,在大环境下,我个人觉得考虑到维护性和开发效率,我推荐直接使用反射写公用方法。