zoukankan      html  css  js  c++  java
  • 公布一个 150 行左右的 ORM

    今天,一个因为 ORM 的性能问题引发了一场血案,唉。。。

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

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

    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Diagnostics;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Reflection;
    using Lenic.Extensions;
     
    namespace Lenic.Data.Extensions
    {
        /// <summary>
        /// IDataReader 扩展方法集合
        /// </summary>
        [DebuggerStepThrough]
        public static class DataReaderExtensions
        {
            #region Private Methods
            private static readonly Dictionary<Type, Delegate> cache = new Dictionary<Type, Delegate>();
            private static readonly object cacheLocker = new object();
            #endregion
     
            #region Business Methods
            /// <summary>
            /// 返回指定字段的值, 并执行 ConvertTo 函数转换。
            /// </summary>
            /// <typeparam name="T">返回值类型。</typeparam>
            /// <param name="reader">一个实现了 IDataReader 接口的实例对象。</param>
            /// <param name="name">要查找的字段的名称。</param>
            /// <returns>转换完毕的 T 类型的结果。</returns>
            public static T Field<T>(this IDataReader reader, string name)
            {
                return reader[name].ConvertTo<T>(default(T), false);
            }
     
            /// <summary>
            /// 返回指定字段的值, 并执行 ConvertTo 函数转换。
            /// </summary>
            /// <typeparam name="T">返回值类型。</typeparam>
            /// <param name="reader">一个实现了 IDataReader 接口的实例对象。</param>
            /// <param name="index">要查找的字段的索引。</param>
            /// <returns>转换完毕的 T 类型的结果。</returns>
            public static T Field<T>(this IDataReader reader, int index)
            {
                return reader[index].ConvertTo<T>(default(T), false);
            }
     
            /// <summary>
            /// 解析当前 IDataReader 类型的实例对象并提取一个 T 类型的列表。
            /// </summary>
            /// <typeparam name="T">待解析的元素类型, 该类型必须包含一个默认的构造函数。</typeparam>
            /// <param name="reader">一个实现了 IDataReader 接口的实例对象。</param>
            /// <returns>一个 T 类型的列表。</returns>
            public static List<T> ToList<T>(this IDataReader reader) where T : class, new()
            {
                return Fill<T>(reader, DynamicCreateEntity<T>()).ToList();
            }
     
            /// <summary>
            /// 解析当前 IDataReader 类型的实例对象并提取一个 T 类型的列表。
            /// </summary>
            /// <typeparam name="T">待解析的元素类型, 该类型必须包含一个默认的构造函数。</typeparam>
            /// <param name="reader">一个实现了 IDataReader 接口的实例对象。</param>
            /// <param name="predicate">映射委托。</param>
            /// <returns>一个 T 类型的列表。</returns>
            public static List<T> ToList<T>(this IDataReader reader, Func<IDataReader, T> predicate)
                where T : class, new()
            {
                return Fill<T>(reader, predicate).ToList();
            }
            #endregion
     
            #region Private Methods
            /// <summary>
            /// 创建一个 构造函数 委托。
            /// </summary>
            /// <typeparam name="T">构造目标类型。</typeparam>
            /// <returns>构造完毕的 Func 委托。</returns>
            private static Func<IDataReader, T> DynamicCreateEntity<T>() where T : class, new()
            {
                var type = typeof(T);
                if (cache.ContainsKey(type))
                    return (Func<IDataReader, T>)cache[type];
     
                lock (cacheLocker)
                {
                    if (cache.ContainsKey(type))
                        return (Func<IDataReader, T>)cache[type];
     
                    var result = DynamicCreateEntityLogic<T>();
                    cache.Add(type, result);
                    return result;
                }
            }
     
            /// <summary>
            /// 创建一个 构造函数 委托(逻辑实现)。
            /// </summary>
            /// <typeparam name="T">构造目标类型。</typeparam>
            /// <returns>构造完毕的 Func 委托。</returns>
            private static Func<IDataReader, T> DynamicCreateEntityLogic<T>() where T : class, new()
            {
                // Compiles a delegate of the form (IDataReader r) => new T { Prop1 = r.Field<Prop1Type>("Prop1"), ... }
                ParameterExpression r = Expression.Parameter(typeof(IDataReader), "r");
     
                // Get Properties of the property can read and write
                var props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)
                    .Where(p => p.CanRead && p.CanWrite)
                    .ToArray();
     
                // Create property bindings for all writable properties
                List<MemberBinding> bindings = new List<MemberBinding>(props.Length);
     
                // Get the binding method
                var method = typeof(DataReaderExtensions).GetMethods()
                    .First(p => p.Name == "Field" &&
                                p.GetParameters().Length == 2 &&
                                p.GetParameters()[1].ParameterType == typeof(string));
     
                foreach (PropertyInfo property in (typeof(T).GetProperties()))
                {
                    // Create expression representing r.Field<property.PropertyType>(property.Name)
                    MethodCallExpression propertyValue = Expression.Call(
                        method.MakeGenericMethod(property.PropertyType),
                        r, Expression.Constant(property.Name));
     
                    // Assign the property value to property through a member binding
                    MemberBinding binding = Expression.Bind(property, propertyValue);
                    bindings.Add(binding);
                }
                // Create the initializer, which instantiates an instance of T and sets property values
     
                // using the member bindings we just created
                Expression initializer = Expression.MemberInit(Expression.New(typeof(T)), bindings);
     
                // Create the lambda expression, which represents the complete delegate (r => initializer)
                Expression<Func<IDataReader, T>> lambda = Expression.Lambda<Func<IDataReader, T>>(initializer, r);
     
                return lambda.Compile();
            }
     
            /// <summary>
            /// 从一个 IDataReader 的实例对象中提取一个 T 类型的列表。
            /// </summary>
            /// <typeparam name="T">结果列表中的元素类型, 该类型必须包含一个默认的构造函数。</typeparam>
            /// <param name="reader">一个实现了 IDataReader 接口的实例对象。</param>
            /// <returns>一个 T 类型的列表。</returns>
            private static IEnumerable<T> Fill<T>(IDataReader reader, Func<IDataReader, T> predicate) where T : class, new()
            {
                while (reader.Read())
                    yield return predicate(reader);
            }
            #endregion
        }
    }

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

    #region Type Convert Extensions
    private static string typeIConvertibleFullName = typeof(IConvertible).FullName;
     
    /// <summary>
    /// 将当前实例对象类型转换为 T 类型.
    /// </summary>
    /// <typeparam name="T">目标类型.</typeparam>
    /// <param name="obj">当前实例.</param>
    /// <returns>转换完成的 T 类型的一个实例对象.</returns>
    public static T ConvertTo<T>(this object obj)
    {
        return ConvertTo(obj, default(T));
    }
     
    /// <summary>
    /// 将当前实例对象类型转换为 T 类型.
    /// </summary>
    /// <typeparam name="T">目标类型.</typeparam>
    /// <param name="obj">当前实例.</param>
    /// <param name="defaultValue">转换失败时的返回值.</param>
    /// <returns>转换完成的 T 类型的一个实例对象.</returns>
    public static T ConvertTo<T>(this object obj, T defaultValue)
    {
        if (obj != null)
        {
            if (obj is T)
                return (T)obj;
     
            var sourceType = obj.GetType();
            var targetType = typeof(T);
     
            if (targetType.IsEnum)
                return (T)Enum.Parse(targetType, obj.ToString(), true);
     
            if (sourceType.GetInterface(typeIConvertibleFullName) != null &&
                targetType.GetInterface(typeIConvertibleFullName) != null)
                return (T)Convert.ChangeType(obj, targetType);
     
            var converter = TypeDescriptor.GetConverter(obj);
            if (converter != null && converter.CanConvertTo(targetType))
                return (T)converter.ConvertTo(obj, targetType);
     
            converter = TypeDescriptor.GetConverter(targetType);
            if (converter != null && converter.CanConvertFrom(sourceType))
                return (T)converter.ConvertFrom(obj);
     
            throw new ApplicationException("convert error.");
        }
        throw new ArgumentNullException("obj");
    }
     
    /// <summary>
    /// 将当前实例对象类型转换为 T 类型.
    /// </summary>
    /// <typeparam name="T">目标类型.</typeparam>
    /// <param name="obj">当前实例.</param>
    /// <param name="defaultValue">转换失败时的返回值.</param>
    /// <param name="ignoreException">如果设置为 <c>true</c> 表示忽略异常信息, 直接返回缺省值.</param>
    /// <returns>转换完成的 T 类型的一个实例对象.</returns>
    public static T ConvertTo<T>(this object obj, T defaultValue, bool ignoreException)
    {
        if (ignoreException)
        {
            try
            {
                return obj.ConvertTo<T>(defaultValue);
            }
            catch
            {
                return defaultValue;
            }
        }
        return obj.ConvertTo<T>(defaultValue);
    }
    #endregion

    再次欢迎大家品鉴。

  • 相关阅读:
    03 获取元素节点对象的方式
    02 window对象的常用方法
    01 BOM对象介绍
    10 for循环介绍和应用
    09 三元运算
    序列化pickle
    随机数random模块
    datetime模块时间运算
    time模块细讲
    时间处理模块
  • 原文地址:https://www.cnblogs.com/lenic/p/2647892.html
Copyright © 2011-2022 走看看