公布一个 150 行左右的 ORM

本文介绍了一种通过Lambda表达式树生成Delegate来优化ORM性能的方法,并提供了一个DataReader扩展方法集合的实现,能够有效地提升数据读取效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天,一个因为 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

 

再次欢迎大家品鉴。

转载于:https://www.cnblogs.com/lenic/archive/2012/08/20/2647892.html

1. 用户与身体信息管理模块 用户信息管理: 注册登录:支持手机号 / 邮箱注册,密码加密存储,提供第三方快捷登录(模拟) 个人资料:记录基本信息(姓名、年龄、性别、身高、体重、职业) 健康目标:用户设置目标(如 “减重 5kg”“增肌”“维持健康”)及期望周期 身体状态跟踪: 体重记录:定期录入体重数据,生成体重变化曲线(折线图) 身体指标:记录 BMI(自动计算)、体脂率(可选)、基础代谢率(根据身高体重估算) 健康状况:用户可填写特殊情况(如糖尿病、过敏食物、素食偏好),系统据此调整推荐 2. 膳食记录与食物数据库模块 食物数据库: 基础信息:包含常见食物(如米饭、鸡蛋、牛肉)的名称、类别(主食 / 肉类 / 蔬菜等)、每份重量 营养成分:记录每 100g 食物的热量(kcal)、蛋白质、脂肪、碳水化合物、维生素、矿物质含量 数据库维护:管理员可添加新食物、更新营养数据,支持按名称 / 类别检索 膳食记录功能: 快速记录:用户选择食物、输入食用量(克 / 份),系统自动计算摄入的营养成分 餐次分类:按早餐 / 午餐 / 晚餐 / 加餐分类记录,支持上传餐食照片(可选) 批量操作:提供常见套餐模板(如 “三明治 + 牛奶”),一键添加到记录 历史记录:按日期查看过往膳食记录,支持编辑 / 删除错误记录 3. 营养分析模块 每日营养摄入分析: 核心指标计算:统计当日摄入的总热量、蛋白质 / 脂肪 / 碳水化合物占比(按每日推荐量对比) 微量营养素分析:检查维生素(如维生素 C、钙、铁)的摄入是否达标 平衡评估:生成 “营养平衡度” 评分(0-100 分),指出摄入过剩或不足的营养素 趋势分析: 周 / 月营养趋势:用折线图展示近 7 天 / 30 天的热量、三大营养素摄入变化 对比分析:将实际摄入与推荐量对比(如 “蛋白质摄入仅达到推荐量的 70%”) 目标达成率:针对健
1. 用户管理模块 用户注册与认证: 注册:用户填写身份信息(姓名、身份证号、手机号)、设置登录密码(需符合复杂度要求),系统生成唯一客户号 登录:支持账号(客户号 / 手机号)+ 密码登录,提供验证码登录、忘记密码(通过手机验证码重置)功能 身份验证:注册后需完成实名认证(模拟上传身份证照片,系统标记认证状态) 个人信息管理: 基本信息:查看 / 修改联系地址、紧急联系人、邮箱等非核心信息(身份证号等关键信息不可修改) 安全设置:修改登录密码、设置交易密码(用于转账等敏感操作)、开启 / 关闭登录提醒 权限控制:普通用户仅能操作本人账户;管理员可管理用户信息、查看系统统计数据 2. 账户与资金管理模块 账户管理: 账户创建:用户可开通储蓄卡账户(默认 1 个主账户,支持最多 3 个子账户,如 “日常消费账户”“储蓄账户”) 账户查询:查看各账户余额、开户日期、状态(正常 / 冻结)、交易限额 账户操作:挂失 / 解挂账户、申请注销账户(需余额为 0) 资金操作: 转账汇款:支持同转账(输入对方账户号 / 手机号),需验证交易密码,可添加常用收款人 存款 / 取款:模拟存款(输入金额增加余额)、取款(输入金额减少余额,需不超过可用余额) 交易记录:按时间、类型(转入 / 转出 / 存款 / 取款)查询明细,显示交易时间、金额、对方账户(脱敏显示)、交易状态 3. 账单与支付模块 账单管理: 月度账单:自动生成每月收支明细,统计总收入、总支出、余额变动 账单查询:按月份、交易类型筛选账单,支持导出为 Excel 格式 还款提醒:若有贷款(简化版可模拟),系统在还款日 3 天前发送提醒 快捷支付: 绑定支付方式:添加银卡(系统内账户)作为支付渠道 模拟消费:支持输入商户名称和金额,完成支付(从账户余额扣减) 支付记录:保存所有消费记录,包含商户、时间、金额、支付状态 4.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值