51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 1651|回复: 1
打印 上一主题 下一主题

公布一个 150 行左右的 ORM

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2018-4-27 11:13:31 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
今天,一个因为 ORM 的性能问题引发了一场血案,唉。。。



突然想起来几年前我写的一个小东西,放上来大家评论一下,有兴趣的可以测试一下性能,呵呵。



原理很简单,利用 Lambda 表达式树生成一个 Delegate ,然后缓存起来。不多说了,下面上代码:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data;
  4. using System.Diagnostics;
  5. using System.Linq;
  6. using System.Linq.Expressions;
  7. using System.Reflection;
  8. using Lenic.Extensions;

  9. namespace Lenic.Data.Extensions
  10. {
  11.     /// <summary>
  12.     /// IDataReader 扩展方法集合
  13.     /// </summary>
  14.     [DebuggerStepThrough]
  15.     public static class DataReaderExtensions
  16.     {
  17.         #region Private Methods
  18.         private static readonly Dictionary<Type, Delegate> cache = new Dictionary<Type, Delegate>();
  19.         private static readonly object cacheLocker = new object();
  20.         #endregion

  21.         #region Business Methods
  22.         /// <summary>
  23.         /// 返回指定字段的值, 并执行 ConvertTo 函数转换。
  24.         /// </summary>
  25.         /// <typeparam name="T">返回值类型。</typeparam>
  26.         /// <param name="reader">一个实现了 IDataReader 接口的实例对象。</param>
  27.         /// <param name="name">要查找的字段的名称。</param>
  28.         /// <returns>转换完毕的 T 类型的结果。</returns>
  29.         public static T Field<T>(this IDataReader reader, string name)
  30.         {
  31.             return reader[name].ConvertTo<T>(default(T), false);
  32.         }

  33.         /// <summary>
  34.         /// 返回指定字段的值, 并执行 ConvertTo 函数转换。
  35.         /// </summary>
  36.         /// <typeparam name="T">返回值类型。</typeparam>
  37.         /// <param name="reader">一个实现了 IDataReader 接口的实例对象。</param>
  38.         /// <param name="index">要查找的字段的索引。</param>
  39.         /// <returns>转换完毕的 T 类型的结果。</returns>
  40.         public static T Field<T>(this IDataReader reader, int index)
  41.         {
  42.             return reader[index].ConvertTo<T>(default(T), false);
  43.         }

  44.         /// <summary>
  45.         /// 解析当前 IDataReader 类型的实例对象并提取一个 T 类型的列表。
  46.         /// </summary>
  47.         /// <typeparam name="T">待解析的元素类型, 该类型必须包含一个默认的构造函数。</typeparam>
  48.         /// <param name="reader">一个实现了 IDataReader 接口的实例对象。</param>
  49.         /// <returns>一个 T 类型的列表。</returns>
  50.         public static List<T> ToList<T>(this IDataReader reader) where T : class, new()
  51.         {
  52.             return Fill<T>(reader, DynamicCreateEntity<T>()).ToList();
  53.         }

  54.         /// <summary>
  55.         /// 解析当前 IDataReader 类型的实例对象并提取一个 T 类型的列表。
  56.         /// </summary>
  57.         /// <typeparam name="T">待解析的元素类型, 该类型必须包含一个默认的构造函数。</typeparam>
  58.         /// <param name="reader">一个实现了 IDataReader 接口的实例对象。</param>
  59.         /// <param name="predicate">映射委托。</param>
  60.         /// <returns>一个 T 类型的列表。</returns>
  61.         public static List<T> ToList<T>(this IDataReader reader, Func<IDataReader, T> predicate)
  62.             where T : class, new()
  63.         {
  64.             return Fill<T>(reader, predicate).ToList();
  65.         }
  66.         #endregion

  67.         #region Private Methods
  68.         /// <summary>
  69.         /// 创建一个 构造函数 委托。
  70.         /// </summary>
  71.         /// <typeparam name="T">构造目标类型。</typeparam>
  72.         /// <returns>构造完毕的 Func 委托。</returns>
  73.         private static Func<IDataReader, T> DynamicCreateEntity<T>() where T : class, new()
  74.         {
  75.             var type = typeof(T);
  76.             if (cache.ContainsKey(type))
  77.                 return (Func<IDataReader, T>)cache[type];

  78.             lock (cacheLocker)
  79.             {
  80.                 if (cache.ContainsKey(type))
  81.                     return (Func<IDataReader, T>)cache[type];

  82.                 var result = DynamicCreateEntityLogic<T>();
  83.                 cache.Add(type, result);
  84.                 return result;
  85.             }
  86.         }

  87.         /// <summary>
  88.         /// 创建一个 构造函数 委托(逻辑实现)。
  89.         /// </summary>
  90.         /// <typeparam name="T">构造目标类型。</typeparam>
  91.         /// <returns>构造完毕的 Func 委托。</returns>
  92.         private static Func<IDataReader, T> DynamicCreateEntityLogic<T>() where T : class, new()
  93.         {
  94.             // Compiles a delegate of the form (IDataReader r) => new T { Prop1 = r.Field<Prop1Type>("Prop1"), ... }
  95.             ParameterExpression r = Expression.Parameter(typeof(IDataReader), "r");

  96.             // Get Properties of the property can read and write
  97.             var props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)
  98.                 .Where(p => p.CanRead && p.CanWrite)
  99.                 .ToArray();

  100.             // Create property bindings for all writable properties
  101.             List<MemberBinding> bindings = new List<MemberBinding>(props.Length);

  102.             // Get the binding method
  103.             var method = typeof(DataReaderExtensions).GetMethods()
  104.                 .First(p => p.Name == "Field" &&
  105.                             p.GetParameters().Length == 2 &&
  106.                             p.GetParameters()[1].ParameterType == typeof(string));

  107.             foreach (PropertyInfo property in (typeof(T).GetProperties()))
  108.             {
  109.                 // Create expression representing r.Field<property.PropertyType>(property.Name)
  110.                 MethodCallExpression propertyValue = Expression.Call(
  111.                     method.MakeGenericMethod(property.PropertyType),
  112.                     r, Expression.Constant(property.Name));

  113.                 // Assign the property value to property through a member binding
  114.                 MemberBinding binding = Expression.Bind(property, propertyValue);
  115.                 bindings.Add(binding);
  116.             }
  117.             // Create the initializer, which instantiates an instance of T and sets property values

  118.             // using the member bindings we just created
  119.             Expression initializer = Expression.MemberInit(Expression.New(typeof(T)), bindings);

  120.             // Create the lambda expression, which represents the complete delegate (r => initializer)
  121.             Expression<Func<IDataReader, T>> lambda = Expression.Lambda<Func<IDataReader, T>>(initializer, r);

  122.             return lambda.Compile();
  123.         }

  124.         /// <summary>
  125.         /// 从一个 IDataReader 的实例对象中提取一个 T 类型的列表。
  126.         /// </summary>
  127.         /// <typeparam name="T">结果列表中的元素类型, 该类型必须包含一个默认的构造函数。</typeparam>
  128.         /// <param name="reader">一个实现了 IDataReader 接口的实例对象。</param>
  129.         /// <returns>一个 T 类型的列表。</returns>
  130.         private static IEnumerable<T> Fill<T>(IDataReader reader, Func<IDataReader, T> predicate) where T : class, new()
  131.         {
  132.             while (reader.Read())
  133.                 yield return predicate(reader);
  134.         }
  135.         #endregion
  136.     }
  137. }
复制代码


上面用到了一个全能转换方法,代码如下:

  1. #region Type Convert Extensions
  2. private static string typeIConvertibleFullName = typeof(IConvertible).FullName;

  3. /// <summary>
  4. /// 将当前实例对象类型转换为 T 类型.
  5. /// </summary>
  6. /// <typeparam name="T">目标类型.</typeparam>
  7. /// <param name="obj">当前实例.</param>
  8. /// <returns>转换完成的 T 类型的一个实例对象.</returns>
  9. public static T ConvertTo<T>(this object obj)
  10. {
  11.     return ConvertTo(obj, default(T));
  12. }

  13. /// <summary>
  14. /// 将当前实例对象类型转换为 T 类型.
  15. /// </summary>
  16. /// <typeparam name="T">目标类型.</typeparam>
  17. /// <param name="obj">当前实例.</param>
  18. /// <param name="defaultValue">转换失败时的返回值.</param>
  19. /// <returns>转换完成的 T 类型的一个实例对象.</returns>
  20. public static T ConvertTo<T>(this object obj, T defaultValue)
  21. {
  22.     if (obj != null)
  23.     {
  24.         if (obj is T)
  25.             return (T)obj;

  26.         var sourceType = obj.GetType();
  27.         var targetType = typeof(T);

  28.         if (targetType.IsEnum)
  29.             return (T)Enum.Parse(targetType, obj.ToString(), true);

  30.         if (sourceType.GetInterface(typeIConvertibleFullName) != null &&
  31.             targetType.GetInterface(typeIConvertibleFullName) != null)
  32.             return (T)Convert.ChangeType(obj, targetType);

  33.         var converter = TypeDescriptor.GetConverter(obj);
  34.         if (converter != null && converter.CanConvertTo(targetType))
  35.             return (T)converter.ConvertTo(obj, targetType);

  36.         converter = TypeDescriptor.GetConverter(targetType);
  37.         if (converter != null && converter.CanConvertFrom(sourceType))
  38.             return (T)converter.ConvertFrom(obj);

  39.         throw new ApplicationException("convert error.");
  40.     }
  41.     throw new ArgumentNullException("obj");
  42. }

  43. /// <summary>
  44. /// 将当前实例对象类型转换为 T 类型.
  45. /// </summary>
  46. /// <typeparam name="T">目标类型.</typeparam>
  47. /// <param name="obj">当前实例.</param>
  48. /// <param name="defaultValue">转换失败时的返回值.</param>
  49. /// <param name="ignoreException">如果设置为 <c>true</c> 表示忽略异常信息, 直接返回缺省值.</param>
  50. /// <returns>转换完成的 T 类型的一个实例对象.</returns>
  51. public static T ConvertTo<T>(this object obj, T defaultValue, bool ignoreException)
  52. {
  53.     if (ignoreException)
  54.     {
  55.         try
  56.         {
  57.             return obj.ConvertTo<T>(defaultValue);
  58.         }
  59.         catch
  60.         {
  61.             return defaultValue;
  62.         }
  63.     }
  64.     return obj.ConvertTo<T>(defaultValue);
  65. }
  66. #endregion
复制代码


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏
回复

使用道具 举报

本版积分规则

关闭

站长推荐上一条 /1 下一条

小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

GMT+8, 2024-9-25 15:17 , Processed in 0.065755 second(s), 23 queries .

Powered by Discuz! X3.2

© 2001-2024 Comsenz Inc.

快速回复 返回顶部 返回列表