首页 > 其他分享 >使用Expression代替反射读取IDataReader或IDataRecord给实体类赋值

使用Expression代替反射读取IDataReader或IDataRecord给实体类赋值

时间:2022-10-25 09:47:44浏览次数:41  
标签:convert 实体类 methodName IDataRecord else typeof propertyType Expression

ExpressionMapper代码

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace LiteSql
{
    /// <summary>
    /// IDataRecord到实体类的映射
    /// </summary>
    internal class ExpressionMapper
    {
        #region 变量
        /// <summary>
        /// 缓存
        /// </summary>
        private static ConcurrentDictionary<string, object> _cacheDict = new ConcurrentDictionary<string, object>();
        #endregion

        #region BindData<T> 数据绑定
        /// <summary>
        /// 数据绑定
        /// </summary>
        public static Func<IDataRecord, T> BindData<T>(PropertyInfoEx[] propertyInfoList, Dictionary<string, int> fields, string strFields)
        {
            Type entityType = typeof(T);
            string key = entityType.FullName + "_" + strFields + "_T";

            if (_cacheDict.TryGetValue(key, out _))
            {
                return _cacheDict[key] as Func<IDataRecord, T>;
            }
            else
            {
                CreateBindings(entityType, propertyInfoList, fields, out ParameterExpression dataRecordExpr, out Expression initExpr);

                Expression<Func<IDataRecord, T>> lambda = Expression.Lambda<Func<IDataRecord, T>>(initExpr, dataRecordExpr);

                var func = lambda.Compile();
                _cacheDict.TryAdd(key, func);
                return func;
            }

        }
        #endregion

        #region BindData 数据绑定
        /// <summary>
        /// 数据绑定
        /// </summary>
        public static Func<IDataRecord, object> BindData(Type entityType, PropertyInfoEx[] propertyInfoList, Dictionary<string, int> fields, string strFields)
        {
            string key = entityType.FullName + "_" + strFields + "_Type";
            if (_cacheDict.TryGetValue(key, out _))
            {
                return _cacheDict[key] as Func<IDataRecord, object>;
            }
            else
            {
                CreateBindings(entityType, propertyInfoList, fields, out ParameterExpression dataRecordExpr, out Expression initExpr);

                Expression<Func<IDataRecord, object>> lambda = Expression.Lambda<Func<IDataRecord, object>>(initExpr, dataRecordExpr);

                var func = lambda.Compile();
                _cacheDict.TryAdd(key, func);
                return func;
            }

        }
        #endregion

        #region CreateBindings 属性绑定
        /// <summary>
        /// 属性绑定
        /// </summary>
        private static void CreateBindings(Type entityType, PropertyInfoEx[] propertyInfoList, Dictionary<string, int> fields, out ParameterExpression dataRecordExpr, out Expression initExpr)
        {
            dataRecordExpr = Expression.Parameter(typeof(IDataRecord), "r");

            List<MemberBinding> bindings = new List<MemberBinding>();

            foreach (PropertyInfoEx propertyInfoEx in propertyInfoList)
            {
                if (!fields.ContainsKey(propertyInfoEx.FieldNameUpper)) continue;

                Expression propertyValue = GetMethodCall(dataRecordExpr, propertyInfoEx, fields[propertyInfoEx.FieldNameUpper]);

                MemberBinding binding = Expression.Bind(propertyInfoEx.PropertyInfo, propertyValue);
                bindings.Add(binding);
            }

            initExpr = Expression.MemberInit(Expression.New(entityType), bindings);
        }
        #endregion

        #region GetMethodCall
        private static Expression GetMethodCall(ParameterExpression dataRecordExpr, PropertyInfoEx propertyInfoEx, int fieldIndex)
        {
            Type propertyType = propertyInfoEx.PropertyInfo.PropertyType;
            Type typeIDataRecord = typeof(IDataRecord);

            GetIDataRecordMethod(propertyType, out string methodName, out bool convert);

            MethodCallExpression getValueExpr = Expression.Call(dataRecordExpr, typeIDataRecord.GetMethod(methodName), Expression.Constant(fieldIndex));

            MethodCallExpression isDBNullExpr = Expression.Call(dataRecordExpr, typeIDataRecord.GetMethod("IsDBNull"), Expression.Constant(fieldIndex));

            if (convert)
            {
                if (propertyType == typeof(Guid) || propertyType == typeof(Guid?))
                {
                    Expression guidExpr = Expression.New(typeof(Guid).GetConstructor(new Type[] { typeof(string) }), getValueExpr);

                    if (propertyType == typeof(Guid))
                    {
                        return Expression.Condition(isDBNullExpr, Expression.Default(propertyType), guidExpr);
                    }
                    else
                    {
                        var convertExpr = Expression.Convert(guidExpr, propertyType);

                        return Expression.Condition(isDBNullExpr, Expression.Default(propertyType), convertExpr);
                    }
                }
                else
                {
                    var convertExpr = Expression.Convert(getValueExpr, propertyType);

                    return Expression.Condition(isDBNullExpr, Expression.Default(propertyType), convertExpr);
                }
            }
            else
            {
                return getValueExpr;
            }
        }
        #endregion

        #region GetIDataRecordMethod
        private static void GetIDataRecordMethod(Type propertyType, out string methodName, out bool convert)
        {
            methodName = "GetString";
            convert = false;

            if (propertyType == typeof(string))
            {
                methodName = "GetString";
                convert = true;
            }
            else if (propertyType == typeof(object))
            {
                methodName = "GetValue";
                convert = true;
            }
            else if (propertyType == typeof(byte[]))
            {
                methodName = "GetValue";
                convert = true;
            }
            else if (propertyType == typeof(Guid))
            {
                methodName = "GetString";
                convert = true;
            }
            else if (propertyType == typeof(char))
            {
                methodName = "GetChar";
            }
            else if (propertyType == typeof(byte))
            {
                methodName = "GetByte";
            }
            else if (propertyType == typeof(sbyte))
            {
                methodName = "GetByte";
            }
            else if (propertyType == typeof(short))
            {
                methodName = "GetInt16";
            }
            else if (propertyType == typeof(ushort))
            {
                methodName = "GetInt16";
            }
            else if (propertyType == typeof(int))
            {
                methodName = "GetInt32";
            }
            else if (propertyType == typeof(uint))
            {
                methodName = "GetInt32";
            }
            else if (propertyType == typeof(long))
            {
                methodName = "GetInt64";
            }
            else if (propertyType == typeof(ulong))
            {
                methodName = "GetInt64";
            }
            else if (propertyType == typeof(float))
            {
                methodName = "GetFloat";
            }
            else if (propertyType == typeof(double))
            {
                methodName = "GetDouble";
            }
            else if (propertyType == typeof(decimal))
            {
                methodName = "GetDecimal";
            }
            else if (propertyType == typeof(bool))
            {
                methodName = "GetBoolean";
            }
            else if (propertyType == typeof(DateTime))
            {
                methodName = "GetDateTime";
            }
            // ======== 以下是可空类型 ================================ 
            else if (propertyType == typeof(Guid?))
            {
                methodName = "GetString";
                convert = true;
            }
            else if (propertyType == typeof(char?))
            {
                methodName = "GetChar";
                convert = true;
            }
            else if (propertyType == typeof(byte?))
            {
                methodName = "GetByte";
                convert = true;
            }
            else if (propertyType == typeof(sbyte?))
            {
                methodName = "GetByte";
                convert = true;
            }
            else if (propertyType == typeof(short?))
            {
                methodName = "GetInt16";
                convert = true;
            }
            else if (propertyType == typeof(ushort?))
            {
                methodName = "GetInt16";
                convert = true;
            }
            else if (propertyType == typeof(int?))
            {
                methodName = "GetInt32";
                convert = true;
            }
            else if (propertyType == typeof(uint?))
            {
                methodName = "GetInt32";
                convert = true;
            }
            else if (propertyType == typeof(long?))
            {
                methodName = "GetInt64";
                convert = true;
            }
            else if (propertyType == typeof(ulong?))
            {
                methodName = "GetInt64";
                convert = true;
            }
            else if (propertyType == typeof(float?))
            {
                methodName = "GetFloat";
                convert = true;
            }
            else if (propertyType == typeof(double?))
            {
                methodName = "GetDouble";
                convert = true;
            }
            else if (propertyType == typeof(decimal?))
            {
                methodName = "GetDecimal";
                convert = true;
            }
            else if (propertyType == typeof(bool?))
            {
                methodName = "GetBoolean";
                convert = true;
            }
            else if (propertyType == typeof(DateTime?))
            {
                methodName = "GetDateTime";
                convert = true;
            }
        }
        #endregion

    }
}

如何使用

实体类列表赋值

private void DataReaderToList<T>(IDataReader rd, ref List<T> list) where T : new()
{
    if (typeof(T) == typeof(int))
    {
        while (rd.Read())
        {
            list.Add((T)rd[0]);
        }
    }
    else if (typeof(T) == typeof(string))
    {
        while (rd.Read())
        {
            list.Add((T)rd[0]);
        }
    }
    else
    {
        PropertyInfoEx[] propertyInfoList = GetEntityProperties(typeof(T));

        int fcnt = rd.FieldCount;
        StringBuilder strFields = new StringBuilder();
        Dictionary<string, int> fields = new Dictionary<string, int>();
        for (int i = 0; i < fcnt; i++)
        {
            string field = rd.GetName(i).ToUpper();
            if (!fields.ContainsKey(field))
            {
                fields.Add(field, i);
                strFields.Append("_" + field);
            }
        }

        var func = ExpressionMapper.BindData<T>(propertyInfoList, fields, strFields.ToString());

        while (rd.Read())
        {
            T obj = func(rd);

            list.Add(obj);
        }
    }
}

实体类赋值

private void DataReaderToEntity(Type type, IDataReader rd, ref object result, ref bool hasValue)
{
    PropertyInfoEx[] propertyInfoList = GetEntityProperties(type);

    int fieldCount = rd.FieldCount;
    StringBuilder strFields = new StringBuilder();
    Dictionary<string, int> fields = new Dictionary<string, int>();
    for (int i = 0; i < fieldCount; i++)
    {
        string field = rd.GetName(i).ToUpper();
        if (!fields.ContainsKey(field))
        {
            fields.Add(field, i);
            strFields.Append("_" + field);
        }
    }

    var func = ExpressionMapper.BindData(type, propertyInfoList, fields, strFields.ToString());

    while (rd.Read())
    {
        hasValue = true;

        result = func(rd);
    }
}

标签:convert,实体类,methodName,IDataRecord,else,typeof,propertyType,Expression
From: https://www.cnblogs.com/s0611163/p/16823822.html

相关文章