用C#打造自己的实体转换器

  说明
尽管随着NoSQL的普及,数据库访问的性能已经非常关注的重点了(可以通过架构来解决这个瓶颈),所以有越来越多的项目使用了ORM来访问和操作数据库,在周公的博客上有一个系列的文章来比较ADO.NET和一些常见的ORM,实际上现在周公业余研究的一个项目中,周公也使用了MyBatisNet(由iBatisNet升级而来)。不过仍然有使用ADO.NET的场合,如果使用ADO.NET则免不了要写大量的将DataTable或者DataReader转换成对应的实体类的代码,经过了大约24小时的编码和测试(非连续的,累计的),周公尝试写了一个辅助工具,它可以将DataTable或者DataReader中的数据自动转换成实体类,这个辅助工具只有两个类,一个是负责转换的类,另一个是Attribute类,用以标识实体类的非静态属性与数据集中的数据列的对应关系。

为了便于使用,将所有代码写在了一个文件里,代码中有详尽的注释,所以在这里就不再介绍其原理和如何实现的了。完整的代码如下:

  1. /// <summary>   
  2. /// 实体阅读器类,可以从DataTable中或者DbDataReader的实例中将数据转换成对应的示例   
  3. /// 作者:周公   
  4. /// 日期:2011-07-17   
  5. /// 博客地址:http://blog.csdn.net/zhoufoxcn 或http://zhoufoxcn.blog.51cto.com   
  6. /// 说明:(1)任何人都可以免费使用,请尽量保持此段说明。   
  7. ///      (2)这个版本还不是最终版本,有任何意见或建议请到http://weibo.com/zhoufoxcn处留言。   
  8. /// </summary>   
  9. public sealed class EntityReader  
  10. {  
  11.     private const BindingFlags BindingFlag = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;  
  12.     //将类型与该类型所有的可写且未被忽略属性之间建立映射   
  13.     private static Dictionary<Type, Dictionary<string, PropertyInfo>> propertyMappings = new Dictionary<Type, Dictionary<string, PropertyInfo>>();  
  14.     //在数据库中常见的存储数据类型(String除外)   
  15.     private static Dictionary<Type, MethodInfo> simpleTypeMappings = new Dictionary<Type, MethodInfo>();  
  16.     //存储Nullable<T>与T的对应关系   
  17.     private static Dictionary<Type, Type> genericTypeMappings = new Dictionary<Type, Type>();  
  18.   
  19.     static EntityReader()  
  20.     {  
  21.         //加载所有的数值类型及字符串类型   
  22.         simpleTypeMappings.Add(typeof(String), GetConvertMethod(typeof(String)));  
  23.         simpleTypeMappings.Add(typeof(Byte), GetConvertMethod(typeof(Byte)));  
  24.         simpleTypeMappings.Add(typeof(SByte), GetConvertMethod(typeof(Char)));  
  25.         simpleTypeMappings.Add(typeof(Char), GetConvertMethod(typeof(Boolean)));  
  26.         simpleTypeMappings.Add(typeof(Boolean), GetConvertMethod(typeof(Boolean)));  
  27.         simpleTypeMappings.Add(typeof(Guid), GetConvertMethod(typeof(Guid)));  
  28.         simpleTypeMappings.Add(typeof(Int16), GetConvertMethod(typeof(Int16)));  
  29.         simpleTypeMappings.Add(typeof(UInt16), GetConvertMethod(typeof(UInt16)));  
  30.         simpleTypeMappings.Add(typeof(Int32), GetConvertMethod(typeof(Int32)));  
  31.         simpleTypeMappings.Add(typeof(UInt32), GetConvertMethod(typeof(UInt32)));  
  32.         simpleTypeMappings.Add(typeof(Int64), GetConvertMethod(typeof(Int64)));  
  33.         simpleTypeMappings.Add(typeof(UInt64), GetConvertMethod(typeof(UInt64)));  
  34.         simpleTypeMappings.Add(typeof(Single), GetConvertMethod(typeof(Single)));  
  35.         simpleTypeMappings.Add(typeof(Double), GetConvertMethod(typeof(Double)));  
  36.         simpleTypeMappings.Add(typeof(Decimal), GetConvertMethod(typeof(Decimal)));  
  37.         simpleTypeMappings.Add(typeof(DateTime), GetConvertMethod(typeof(DateTime)));  
  38.         simpleTypeMappings.Add(typeof(TimeSpan), GetConvertMethod(typeof(TimeSpan)));  
  39.         simpleTypeMappings.Add(typeof(Enum), GetConvertMethod(typeof(Enum)));  
  40.   
  41.         genericTypeMappings.Add(typeof(Byte?), typeof(Byte));  
  42.         genericTypeMappings.Add(typeof(SByte?), typeof(SByte));  
  43.         genericTypeMappings.Add(typeof(Char?), typeof(Char));  
  44.         genericTypeMappings.Add(typeof(Boolean?), typeof(Boolean));  
  45.         genericTypeMappings.Add(typeof(Guid?), typeof(Guid));  
  46.         genericTypeMappings.Add(typeof(Int16), typeof(Int16));  
  47.         genericTypeMappings.Add(typeof(UInt16), typeof(UInt16));  
  48.         genericTypeMappings.Add(typeof(Int32), typeof(Int32));  
  49.         genericTypeMappings.Add(typeof(UInt32), typeof(UInt32));  
  50.         genericTypeMappings.Add(typeof(Int64), typeof(Int64));  
  51.         genericTypeMappings.Add(typeof(UInt64), typeof(UInt64));  
  52.         genericTypeMappings.Add(typeof(Single), typeof(Single));  
  53.         genericTypeMappings.Add(typeof(Double), typeof(Double));  
  54.         genericTypeMappings.Add(typeof(Decimal), typeof(Decimal));  
  55.         genericTypeMappings.Add(typeof(DateTime), typeof(DateTime));  
  56.         genericTypeMappings.Add(typeof(TimeSpan), typeof(TimeSpan));  
  57.         genericTypeMappings.Add(typeof(Enum), typeof(Enum));  
  58.   
  59.     }  
  60.     /// <summary>   
  61.     /// 将DataTable中的所有数据转换成List>T<集合   
  62.     /// </summary>   
  63.     /// <typeparam name="T">DataTable中每条数据可以转换的数据类型</typeparam>   
  64.     /// <param name="dataTable">包含有可以转换成数据类型T的数据集合</param>   
  65.     /// <returns></returns>   
  66.     public static List<T> GetEntities<T>(DataTable dataTable) where T : new()  
  67.     {  
  68.         if (dataTable == null)  
  69.         {  
  70.             throw new ArgumentNullException("dataTable");  
  71.         }  
  72.         //如果T的类型满足以下条件:字符串、ValueType或者是Nullable<ValueType>   
  73.         if(typeof(T)==typeof(string)||typeof(T).IsValueType)  
  74.         {  
  75.             return GetSimpleEntities<T>(dataTable);  
  76.         }  
  77.         else  
  78.         {  
  79.             return GetComplexEntities<T>(dataTable);  
  80.         }  
  81.     }  
  82.     /// <summary>   
  83.     /// 将DbDataReader中的所有数据转换成List>T<集合   
  84.     /// </summary>   
  85.     /// <typeparam name="T">DbDataReader中每条数据可以转换的数据类型</typeparam>   
  86.     /// <param name="dataTable">包含有可以转换成数据类型T的DbDataReader实例</param>   
  87.     /// <returns></returns>   
  88.     public static List<T> GetEntities<T>(DbDataReader reader) where T : new()  
  89.     {  
  90.         List<T> list = new List<T>();  
  91.         if (reader == null)  
  92.         {  
  93.             throw new ArgumentNullException("reader");  
  94.         }  
  95.         //如果T的类型满足以下条件:字符串、ValueType或者是Nullable<ValueType>   
  96.         if (typeof(T) == typeof(string) || typeof(T).IsValueType)  
  97.         {  
  98.             return GetSimpleEntities<T>(reader);  
  99.         }  
  100.         else  
  101.         {  
  102.             return GetComplexEntities<T>(reader);  
  103.         }  
  104.   
  105.     }  
  106.     /// <summary>   
  107.     /// 从DataTable中将每一行的第一列转换成T类型的数据   
  108.     /// </summary>   
  109.     /// <typeparam name="T">要转换的目标数据类型</typeparam>   
  110.     /// <param name="dataTable">包含有可以转换成数据类型T的数据集合</param>   
  111.     /// <returns></returns>   
  112.     private static List<T> GetSimpleEntities<T>(DataTable dataTable) where T : new()  
  113.     {  
  114.         List<T> list = new List<T>();  
  115.         foreach (DataRow row in dataTable.Rows)  
  116.         {  
  117.             list.Add((T)GetValueFromObject(row[0], typeof(T)));  
  118.         }  
  119.         return list;  
  120.     }  
  121.     /// <summary>   
  122.     /// 将指定的 Object 的值转换为指定类型的值。   
  123.     /// </summary>   
  124.     /// <param name="value">实现 IConvertible 接口的 Object,或者为 null</param>   
  125.     /// <param name="targetType">要转换的目标数据类型</param>   
  126.     /// <returns></returns>   
  127.     private static object GetValueFromObject(object value, Type targetType)  
  128.     {  
  129.         if (targetType == typeof(string))//如果要将value转换成string类型   
  130.         {  
  131.             return GetString(value);  
  132.         }  
  133.         else if (targetType.IsGenericType)//如果目标类型是泛型   
  134.         {  
  135.             return GetGenericValueFromObject(value, targetType);  
  136.         }  
  137.         else//如果是基本数据类型(包括数值类型、枚举和Guid)   
  138.         {  
  139.             return GetNonGenericValueFromObject(value, targetType);  
  140.         }  
  141.     }  
  142.   
  143.     /// <summary>   
  144.     /// 从DataTable中读取复杂数据类型集合   
  145.     /// </summary>   
  146.     /// <typeparam name="T">要转换的目标数据类型</typeparam>   
  147.     /// <param name="dataTable">包含有可以转换成数据类型T的数据集合</param>   
  148.     /// <returns></returns>   
  149.     private static List<T> GetComplexEntities<T>(DataTable dataTable) where T : new()  
  150.     {  
  151.         if (!propertyMappings.ContainsKey(typeof(T)))  
  152.         {  
  153.             GenerateTypePropertyMapping(typeof(T));  
  154.         }  
  155.         List<T> list = new List<T>();  
  156.         Dictionary<string, PropertyInfo> properties = propertyMappings[typeof(T)];  
  157.         foreach (DataRow row in dataTable.Rows)  
  158.         {  
  159.             T t = new T();  
  160.             foreach (KeyValuePair<string, PropertyInfo> item in properties)  
  161.             {  
  162.                 //如果在DataTable的列中找不到与类属性名对应的列,则忽略   
  163.                 if (row[item.Key] == null)  
  164.                 {  
  165.                     continue;  
  166.                 }  
  167.                 else  
  168.                 {  
  169.                     item.Value.SetValue(t, GetValueFromObject(row[item.Key], item.Value.PropertyType), null);  
  170.                 }  
  171.             }  
  172.             list.Add(t);  
  173.         }  
  174.         return list;  
  175.     }  
  176.   
  177.     /// <summary>   
  178.     /// 从DbDataReader的实例中读取复杂的数据类型   
  179.     /// </summary>   
  180.     /// <typeparam name="T">要转换的目标类</typeparam>   
  181.     /// <param name="reader">DbDataReader的实例</param>   
  182.     /// <returns></returns>   
  183.     private static List<T> GetComplexEntities<T>(DbDataReader reader) where T : new()  
  184.     {  
  185.         if (!propertyMappings.ContainsKey(typeof(T)))//检查当前是否已经有该类与类的可写属性之间的映射   
  186.         {  
  187.             GenerateTypePropertyMapping(typeof(T));  
  188.         }  
  189.         List<T> list = new List<T>();  
  190.         Dictionary<string, PropertyInfo> properties = propertyMappings[typeof(T)];  
  191.         T t = default(T);  
  192.         while (reader.Read())  
  193.         {  
  194.             t = new T();  
  195.             foreach (KeyValuePair<string, PropertyInfo> item in properties)  
  196.             {  
  197.                 if (reader[item.Key] == null)//如果在reader的列中找不到与类属性名对应的列,则忽略   
  198.                 {  
  199.                     continue;  
  200.                 }  
  201.                 else  
  202.                 {  
  203.                     item.Value.SetValue(t, GetValueFromObject(reader[item.Key], item.Value.PropertyType), null);  
  204.                 }  
  205.             }  
  206.             list.Add(t);  
  207.         }  
  208.         return list;  
  209.     }  
  210.     /// <summary>   
  211.     /// 从DbDataReader的实例中读取简单数据类型(String,ValueType)   
  212.     /// </summary>   
  213.     /// <typeparam name="T">目标数据类型</typeparam>   
  214.     /// <param name="reader">DbDataReader的实例</param>   
  215.     /// <returns></returns>   
  216.     private static List<T> GetSimpleEntities<T>(DbDataReader reader)  
  217.     {  
  218.         List<T> list = new List<T>();  
  219.         while (reader.Read())  
  220.         {  
  221.             list.Add((T)GetValueFromObject(reader[0], typeof(T)));  
  222.         }  
  223.         return list;  
  224.     }  
  225.     /// <summary>   
  226.     /// 将Object转换成字符串类型   
  227.     /// </summary>   
  228.     /// <param name="value">object类型的实例</param>   
  229.     /// <returns></returns>   
  230.     private static object GetString(object value)  
  231.     {  
  232.         return Convert.ToString(value);  
  233.     }  
  234.   
  235.     /// <summary>   
  236.     /// 将Object类型数据转换成对应的可空数值类型表示   
  237.     /// </summary>   
  238.     /// <param name="value">实现 IConvertible 接口的 Object,或者为 null</param>   
  239.     /// <param name="targetType">可空数值类型</param>   
  240.     /// <returns></returns>   
  241.     private static object GetGenericValueFromObject(object value,Type targetType)  
  242.     {  
  243.         if (value == DBNull.Value)  
  244.         {  
  245.             return null;  
  246.         }  
  247.         else  
  248.         {  
  249.             //获取可空数值类型对应的基本数值类型,如int?->int,long?->long   
  250.             Type nonGenericType= genericTypeMappings[targetType];  
  251.             return GetNonGenericValueFromObject(value, nonGenericType);  
  252.         }  
  253.     }  
  254.     /// <summary>   
  255.     /// 将指定的 Object 的值转换为指定枚举类型的值。   
  256.     /// </summary>   
  257.     /// <param name="value">实现 IConvertible 接口的 Object,或者为 null</param>   
  258.     /// <param name="targetType"></param>   
  259.     /// <returns></returns>   
  260.     private static object GetEnum(object value,Type targetType)  
  261.     {  
  262.         return Enum.Parse(targetType,value.ToString());  
  263.     }  
  264.   
  265.     /// <summary>   
  266.     /// 将指定的 Object 的值转换为指定类型的值。   
  267.     /// </summary>   
  268.     /// <param name="value">实现 IConvertible 接口的 Object,或者为 null</param>   
  269.     /// <param name="targetType">目标对象的类型</param>   
  270.     /// <returns></returns>   
  271.     private static object GetNonGenericValueFromObject(object value, Type targetType)  
  272.     {  
  273.         if (targetType.IsEnum)//因为   
  274.         {  
  275.             return GetEnum(value, targetType);  
  276.         }  
  277.         else  
  278.         {  
  279.             switch (targetType.Name)  
  280.             {  
  281.                 case "Byte"return GetValueFromObject<Byte>(value);  
  282.                 case "SByte"return GetValueFromObject<SByte>(value);  
  283.                 case "Char"return GetValueFromObject<Char>(value);  
  284.                 case "Boolean"return GetValueFromObject<Boolean>(value);  
  285.                 case "Guid"return GetValueFromObject<Guid>(value);  
  286.                 case "Int16"return GetValueFromObject<Int16>(value);  
  287.                 case "UInt16"return GetValueFromObject<UInt16>(value);  
  288.                 case "Int32"return GetValueFromObject<Int32>(value);  
  289.                 case "UInt32"return GetValueFromObject<UInt32>(value);  
  290.                 case "Int64"return GetValueFromObject<Int64>(value);  
  291.                 case "UInt64"return GetValueFromObject<UInt64>(value);  
  292.                 case "Single"return GetValueFromObject<Single>(value);  
  293.                 case "Double"return GetValueFromObject<Double>(value);  
  294.                 case "Decimal"return GetValueFromObject<Decimal>(value);  
  295.                 case "DateTime"return GetValueFromObject<DateTime>(value);  
  296.                 case "TimeSpan"return GetValueFromObject<TimeSpan>(value);  
  297.                 defaultreturn null;  
  298.             }  
  299.         }  
  300.     }  
  301.   
  302.     /// <summary>   
  303.     /// 将指定的 Object 的值转换为指定类型的值。   
  304.     /// </summary>   
  305.     /// <typeparam name="T">期望转换的目标对象</typeparam>   
  306.     /// <param name="value">实现 IConvertible 接口的 Object,或者为 null</param>   
  307.     /// <returns></returns>   
  308.     private static T GetValueFromObject<T>(object value) where T:new()  
  309.     {  
  310.         //如果可以obj是T的子类   
  311.         if (value is T)  
  312.         {  
  313.             return (T)value;  
  314.         }  
  315.         else if (typeof(T).IsEnum)  
  316.         {  
  317.             return (T)Enum.Parse(typeof(T), value.ToString());  
  318.         }  
  319.         else if (typeof(T) == typeof(Boolean))  
  320.         {  
  321.             object result = null;  
  322.             if (value.ToString() == "1")  
  323.             {  
  324.                 result = true;  
  325.             }  
  326.             else  
  327.             {  
  328.                 result = false;  
  329.             }  
  330.             return (T)result;  
  331.         }  
  332.         else if (typeof(T) == typeof(Guid))  
  333.         {  
  334.             ConstructorInfo constructorInfo = typeof(T).GetConstructor(new Type[] { typeof(string) });  
  335.             return (T)constructorInfo.Invoke(new object[] { value.ToString() });  
  336.         }  
  337.         else  
  338.         {  
  339.             MethodInfo method = simpleTypeMappings[typeof(T)];  
  340.             //调用该类型的转换方法来转换   
  341.             return (T)(method.Invoke(nullnew object[] { value.ToString() }));  
  342.         }  
  343.     }  
  344.   
  345.     /// <summary>   
  346.     /// 获取该类型中属性与数据库字段的对应关系映射   
  347.     /// </summary>   
  348.     /// <param name="type"></param>   
  349.     private static void GenerateTypePropertyMapping(Type type)  
  350.     {  
  351.         if (type != null)  
  352.         {  
  353.             PropertyInfo[] properties = type.GetProperties(BindingFlag);  
  354.             Dictionary<string, PropertyInfo> propertyColumnMapping = new Dictionary<string, PropertyInfo>(properties.Length);  
  355.             string description = string.Empty;  
  356.             Attribute[] attibutes = null;  
  357.             string columnName = string.Empty;  
  358.             bool ignorable = false;  
  359.             foreach (PropertyInfo p in properties)  
  360.             {  
  361.                 columnName = string.Empty;  
  362.                 attibutes = Attribute.GetCustomAttributes(p);  
  363.                 foreach (Attribute attribute in attibutes)  
  364.                 {  
  365.                     //检查是否设置了ColumnName属性   
  366.                     if (attribute.GetType() == typeof(ColumnNameAttribute))  
  367.                     {  
  368.                         columnName = ((ColumnNameAttribute)attribute).ColumnName;  
  369.                         ignorable = ((ColumnNameAttribute)attribute).Ignorable;  
  370.                         break;  
  371.                     }  
  372.                 }  
  373.                 //如果该属性是可读并且未被忽略的,则有可能在实例化该属性对应的类时用得上   
  374.                 if (p.CanWrite&&!ignorable)  
  375.                 {  
  376.                     //如果没有设置ColumnName属性,则直接将该属性名作为数据库字段的映射   
  377.                     if (string.IsNullOrEmpty(columnName))  
  378.                     {  
  379.                         columnName = p.Name;  
  380.                     }  
  381.                     propertyColumnMapping.Add(columnName, p);  
  382.                 }  
  383.             }  
  384.             propertyMappings.Add(type, propertyColumnMapping);  
  385.         }  
  386.     }  
  387.       
  388.     /// <summary>   
  389.     /// 根据对应的目标Type从Convert类中找到对应的转换方法   
  390.     /// </summary>   
  391.     /// <param name="targetType">对应的目标Type</param>   
  392.     /// <returns></returns>   
  393.     private static MethodInfo GetConvertMethod(Type targetType)  
  394.     {  
  395.         if (targetType == typeof(Enum) || targetType == typeof(Guid))  
  396.         {  
  397.             return null;  
  398.         }  
  399.         else if (targetType == typeof(Boolean))  
  400.         {  
  401.             return typeof(Convert).GetMethod("To" + targetType.Name, new Type[] { typeof(object) });  
  402.         }  
  403.         else if (targetType.IsValueType)//如果目标类型是除enum之外的值类型,调用该类型的Parse()方法   
  404.         {  
  405.             return targetType.GetMethod("Parse"new Type[] { typeof(string) });  
  406.         }  
  407.         else//如果目标类型是string,调用Convert.ToString()方法   
  408.         {  
  409.             return typeof(Convert).GetMethod("To" + targetType.Name, new Type[] { typeof(object) });  
  410.         }  
  411.     }  
  412. }  
  413. /// <summary>   
  414. /// 自定义属性,用于指示如何从DataTable或者DbDataReader中读取类的属性值   
  415. /// </summary>   
  416. public class ColumnNameAttribute : Attribute  
  417. {  
  418.     /// <summary>   
  419.     /// 类属性对应的列名   
  420.     /// </summary>   
  421.     public string ColumnName { getset; }  
  422.     /// <summary>   
  423.     /// 指示在从DataTable或者DbDataReader中读取类的属性时是否可以忽略这个属性   
  424.     /// </summary>   
  425.     public bool Ignorable { getset; }  
  426.     /// <summary>   
  427.     /// 构造函数   
  428.     /// </summary>   
  429.     /// <param name="columnName">类属性对应的列名</param>   
  430.     public ColumnNameAttribute(string columnName)  
  431.     {  
  432.         ColumnName = columnName;  
  433.         Ignorable = false;  
  434.     }  
  435.     /// <summary>   
  436.     /// 构造函数   
  437.     /// </summary>   
  438.     /// <param name="ignorable">指示在从DataTable或者DbDataReader中读取类的属性时是否可以忽略这个属性</param>   
  439.     public ColumnNameAttribute(bool ignorable)  
  440.     {  
  441.         Ignorable = ignorable;  
  442.     }  
  443.     /// <summary>   
  444.     /// 构造函数   
  445.     /// </summary>   
  446.     /// <param name="columnName">类属性对应的列名</param>   
  447.     /// <param name="ignorable">指示在从DataTable或者DbDataReader中读取类的属性时是否可以忽略这个属性</param>   
  448.     public ColumnNameAttribute(string columnName, bool ignorable)  
  449.     {  
  450.         ColumnName = columnName;  
  451.         Ignorable = ignorable;  
  452.     }  
  453. }  


在本代码中所用到的实体类代码如下:

  1. public class TY_ContentInfo  
  2. {  
  3.   
  4. public int Id { getset; }  
  5.   
  6. public int ArticleId { getset; }  
  7.   
  8. public string Content { getset; }  
  9.   
  10. public DateTime CreateAt { getset; }  
  11.   
  12. public string ContentHash { getset; }  
  13.   
  14. [ColumnName(true)]  
  15. public bool IsVisible { getset; }  
  16. }  

用法举例
这里以MySQL为例(因为公司不允许安装破解和盗版软件,所以我的电脑上只有免费的SQLite和MySQL社区版了)。

  1. MySqlConnection connection = new MySqlConnection("Server=localhost;Database=crawldb;Uid=root;Pwd=root;Port=3306;");  
  2. MySqlCommand command = new MySqlCommand("SELECT * FROM TY_Content order by Id desc limit 0,200000", connection);  
  3. MySqlDataAdapter adapter = new MySqlDataAdapter(command);  
  4. DataTable data6 = new DataTable();  
  5. adapter.Fill(data6);  
  6. Console.WriteLine("MySQL");  
  7. watch.Reset();  
  8. watch.Start();  
  9. List<TY_ContentInfo> list6 = EntityReader.GetEntities<TY_ContentInfo>(data6);  
  10. watch.Stop();  
  11. Console.WriteLine("Parse data in DataTable lasts ms:{0}", watch.ElapsedMilliseconds);  
  12. Console.WriteLine("Data record Count:{0}", list6.Count);  
  13. data6.Clear();  
  14. data6.Dispose();  
  15. list6.Clear();  
  16. list6 = null;  

性能测试数据

在SQLite上有表如下:

  1. CREATE TABLE TY_Content (  
  2.    Id            integer NOT NULL PRIMARY KEY UNIQUE,  
  3.    ArticleId            int                  not null,  
  4.    Content              text                 not null,  
  5.    ContentHash          varchar(32)          not null,  
  6.    CreateAt             datetime             null default CURRENT_TIMESTAMP  
  7. );  
  8.   
  9. CREATE UNIQUE INDEX IDX_ContentHash on TY_Content (  
  10. ContentHash ASC  
  11. );  

里面共有数据128062条,采用DataTable和SQLiteDataReader的方式读取耗时分别为1582ms和11120ms。
在MySQL中也存在有上面结构的表,有数据175616条,采用DataTable和SQLiteDataReader的方式读取耗时分别为1958ms和9461ms。
在数据库记录条数百万级以下,使用它还可以可以的,实际上在真实的开发中不可能一次性读取数十万条数据的,因此还可以可用于一般的中小型网站。


未尽事宜
第一个未尽事宜就是我还在分析为什么从DataTable中读取比DataReader中读取要快,即使不同数据库都是如此,几乎相差一个数量级,这跟平时我们印象中“从DataReader中读数据要比DataTable中快”相冲突。
第二个未尽事宜是代码的优化问题,因为最近个人事情比较多,还有很多地方没有来得及优化,甚至我的另一种实现还没有比较,那就是采用分而治之的方式,针对每一种数据类型都写一种方法来处理,这样就可以去掉反射部分了,或许速度上还会有提高,但这还是我的预想,没有验证。


总结

上面是一个逻辑稍微有点复杂的例子,里面用到了反射、Attribute及ADO.NET的例子,可以作为想学习这方面知识的朋友一个范例。除此之外,还可以将这个类用于中小型系统开发中。
如果大家有什么好的意见或建议,或者发现了bug,请在博客下方留言或者到http://weibo.com/zhoufoxcn上留言。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值