使用Expression代替反射读取IDataReader或IDataRecord给实体类赋值
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, Dictionary<string, Type> fieldTypes, 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, fieldTypes, 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, Dictionary<string, Type> fieldTypes, 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, fieldTypes, 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, Dictionary<string, Type> fieldTypes, 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], fieldTypes[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 fieldType)
{
Type propertyType = propertyInfoEx.PropertyInfo.PropertyType;
Type typeIDataRecord = typeof(IDataRecord);
string methodName = GetIDataRecordMethod(ref fieldType);
MethodCallExpression getValueExpr = Expression.Call(dataRecordExpr, typeIDataRecord.GetMethod(methodName), Expression.Constant(fieldIndex));
MethodCallExpression isDBNullExpr = Expression.Call(dataRecordExpr, typeIDataRecord.GetMethod("IsDBNull"), Expression.Constant(fieldIndex));
var convertExpr = GetConvertExpr(propertyType, fieldType, getValueExpr);
return Expression.Condition(isDBNullExpr, Expression.Default(propertyType), convertExpr);
}
#endregion
#region GetConvertExpr
private static Expression GetConvertExpr(Type propertyType, Type fieldType, Expression getValueExpr)
{
Expression convertExpr = null;
Type genericType = null;
if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
genericType = propertyType.GenericTypeArguments[0];
}
string methodName = GetConvertMethod(propertyType, out Type methodReturnType);
if (propertyType != fieldType)
{
if (genericType != null)
{
if (genericType == typeof(Guid))
{
Expression newGuidExpr = Expression.New(typeof(Guid).GetConstructor(new Type[] { typeof(string) }), getValueExpr);
convertExpr = Expression.Convert(newGuidExpr, propertyType);
}
else if (genericType != fieldType)
{
convertExpr = Expression.Call(typeof(Convert).GetMethod(methodName, new Type[] { fieldType }), getValueExpr);
convertExpr = Expression.Convert(convertExpr, propertyType);
}
else
{
convertExpr = Expression.Convert(getValueExpr, propertyType);
}
}
else
{
if (propertyType == typeof(Guid))
{
Expression newGuidExpr = Expression.New(typeof(Guid).GetConstructor(new Type[] { typeof(string) }), getValueExpr);
convertExpr = newGuidExpr;
}
else if (methodName != null && methodReturnType != fieldType)
{
convertExpr = Expression.Call(typeof(Convert).GetMethod(methodName, new Type[] { fieldType }), getValueExpr);
if (propertyType != methodReturnType)
{
convertExpr = Expression.Convert(convertExpr, propertyType);
}
}
else
{
if (propertyType != methodReturnType || propertyType == typeof(byte[]))
{
convertExpr = Expression.Convert(getValueExpr, propertyType);
}
else if (propertyType != methodReturnType || propertyType.BaseType == typeof(Array))
{
convertExpr = Expression.Convert(getValueExpr, propertyType);
}
else
{
convertExpr = getValueExpr;
}
}
}
}
else
{
convertExpr = getValueExpr;
}
return convertExpr;
}
#endregion
#region GetIDataRecordMethod 获取IDataRecord方法名称和返回值类型
/// <summary>
/// 获取IDataRecord方法名称和返回值类型
/// </summary>
private static string GetIDataRecordMethod(ref Type fieldType)
{
string methodName = "GetValue";
if (fieldType == typeof(string))
{
methodName = "GetString";
}
else if (fieldType == typeof(object))
{
methodName = "GetValue";
}
else if (fieldType == typeof(byte[]))
{
methodName = "GetValue";
fieldType = typeof(object);
}
else if (fieldType == typeof(Guid))
{
methodName = "GetString";
fieldType = typeof(string);
}
else if (fieldType == typeof(char))
{
methodName = "GetChar";
}
else if (fieldType == typeof(byte))
{
methodName = "GetByte";
}
else if (fieldType == typeof(sbyte))
{
methodName = "GetValue";
fieldType = typeof(object);
}
else if (fieldType == typeof(short))
{
methodName = "GetInt16";
}
else if (fieldType == typeof(ushort))
{
methodName = "GetValue";
fieldType = typeof(object);
}
else if (fieldType == typeof(int))
{
methodName = "GetInt32";
}
else if (fieldType == typeof(uint))
{
methodName = "GetValue";
fieldType = typeof(object);
}
else if (fieldType == typeof(long))
{
methodName = "GetInt64";
}
else if (fieldType == typeof(ulong))
{
methodName = "GetValue";
fieldType = typeof(object);
}
else if (fieldType == typeof(float))
{
methodName = "GetFloat";
}
else if (fieldType == typeof(double))
{
methodName = "GetDouble";
}
else if (fieldType == typeof(decimal))
{
methodName = "GetDecimal";
}
else if (fieldType == typeof(bool))
{
methodName = "GetBoolean";
}
else if (fieldType == typeof(DateTime))
{
methodName = "GetDateTime";
}
// ======== 以下是可空类型 ================================
else if (fieldType == typeof(Guid?))
{
methodName = "GetString";
fieldType = typeof(string);
}
else if (fieldType == typeof(char?))
{
methodName = "GetChar";
fieldType = typeof(char);
}
else if (fieldType == typeof(byte?))
{
methodName = "GetByte";
fieldType = typeof(byte);
}
else if (fieldType == typeof(sbyte?))
{
methodName = "GetValue";
fieldType = typeof(object);
}
else if (fieldType == typeof(short?))
{
methodName = "GetInt16";
fieldType = typeof(short);
}
else if (fieldType == typeof(ushort?))
{
methodName = "GetValue";
fieldType = typeof(object);
}
else if (fieldType == typeof(int?))
{
methodName = "GetInt32";
fieldType = typeof(int);
}
else if (fieldType == typeof(uint?))
{
methodName = "GetValue";
fieldType = typeof(object);
}
else if (fieldType == typeof(long?))
{
methodName = "GetInt64";
fieldType = typeof(long);
}
else if (fieldType == typeof(ulong?))
{
methodName = "GetValue";
fieldType = typeof(object);
}
else if (fieldType == typeof(float?))
{
methodName = "GetFloat";
fieldType = typeof(float);
}
else if (fieldType == typeof(double?))
{
methodName = "GetDouble";
fieldType = typeof(double);
}
else if (fieldType == typeof(decimal?))
{
methodName = "GetDecimal";
fieldType = typeof(decimal);
}
else if (fieldType == typeof(bool?))
{
methodName = "GetBoolean";
fieldType = typeof(bool);
}
else if (fieldType == typeof(DateTime?))
{
methodName = "GetDateTime";
fieldType = typeof(DateTime);
}
return methodName;
}
#endregion
#region GetConvertMethod 获取Convert类的方法名称和返回值类型
/// <summary>
/// 获取Convert类的方法名称和返回值类型
/// </summary>
private static string GetConvertMethod(Type propertyType, out Type methodReturnType)
{
string methodName = null;
methodReturnType = propertyType;
if (propertyType == typeof(string))
{
methodName = "ToString";
}
else if (propertyType == typeof(char))
{
methodName = "ToChar";
}
else if (propertyType == typeof(byte))
{
methodName = "ToByte";
}
else if (propertyType == typeof(sbyte))
{
methodName = "ToByte";
methodReturnType = typeof(byte);
}
else if (propertyType == typeof(short))
{
methodName = "ToInt16";
}
else if (propertyType == typeof(ushort))
{
methodName = "ToInt16";
methodReturnType = typeof(short);
}
else if (propertyType == typeof(int))
{
methodName = "ToInt32";
}
else if (propertyType == typeof(uint))
{
methodName = "ToInt32";
methodReturnType = typeof(int);
}
else if (propertyType == typeof(long))
{
methodName = "ToInt64";
}
else if (propertyType == typeof(ulong))
{
methodName = "ToInt64";
methodReturnType = typeof(long);
}
else if (propertyType == typeof(float))
{
methodName = "ToSingle";
}
else if (propertyType == typeof(double))
{
methodName = "ToDouble";
}
else if (propertyType == typeof(decimal))
{
methodName = "ToDecimal";
}
else if (propertyType == typeof(bool))
{
methodName = "ToBoolean";
}
else if (propertyType == typeof(DateTime))
{
methodName = "ToDateTime";
}
// ======== 以下是可空类型 ================================
else if (propertyType == typeof(char?))
{
methodName = "ToChar";
}
else if (propertyType == typeof(byte?))
{
methodName = "ToByte";
}
else if (propertyType == typeof(sbyte?))
{
methodName = "ToByte";
methodReturnType = typeof(byte);
}
else if (propertyType == typeof(short?))
{
methodName = "ToInt16";
}
else if (propertyType == typeof(ushort?))
{
methodName = "ToInt16";
methodReturnType = typeof(short);
}
else if (propertyType == typeof(int?))
{
methodName = "ToInt32";
}
else if (propertyType == typeof(uint?))
{
methodName = "ToInt32";
methodReturnType = typeof(int);
}
else if (propertyType == typeof(long?))
{
methodName = "ToInt64";
}
else if (propertyType == typeof(ulong?))
{
methodName = "ToInt64";
methodReturnType = typeof(long);
}
else if (propertyType == typeof(float?))
{
methodName = "ToSingle";
}
else if (propertyType == typeof(double?))
{
methodName = "ToDouble";
}
else if (propertyType == typeof(decimal?))
{
methodName = "ToDecimal";
}
else if (propertyType == typeof(bool?))
{
methodName = "ToBoolean";
}
else if (propertyType == typeof(DateTime?))
{
methodName = "ToDateTime";
}
return methodName;
}
#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>();
Dictionary<string, Type> fieldTypes = new Dictionary<string, Type>();
for (int i = 0; i < fcnt; i++)
{
string field = rd.GetName(i).ToUpper();
if (!fields.ContainsKey(field))
{
fields.Add(field, i);
fieldTypes.Add(field, rd.GetFieldType(i));
strFields.Append("_" + field);
}
}
var func = ExpressionMapper.BindData<T>(propertyInfoList, fields, fieldTypes, 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>();
Dictionary<string, Type> fieldTypes = new Dictionary<string, Type>();
for (int i = 0; i < fieldCount; i++)
{
string field = rd.GetName(i).ToUpper();
if (!fields.ContainsKey(field))
{
fields.Add(field, i);
fieldTypes.Add(field, rd.GetFieldType(i));
strFields.Append("_" + field);
}
}
var func = ExpressionMapper.BindData(type, propertyInfoList, fields, fieldTypes, strFields.ToString());
while (rd.Read())
{
hasValue = true;
result = func(rd);
}
}
使用Expression代替反射读取IDataReader或IDataRecord给实体类赋值的更多相关文章
- 读取Excel文件存储在实体类中
1.Maven文件 <!--读取Excel的架包--> <dependency> <groupId>org.apache.poi</groupId> & ...
- [转]C#反射,根据反射将数据库查询数据和实体类绑定,并未实体类赋值
本文来自:http://www.cnblogs.com/mrchenzh/archive/2010/05/31/1747937.html /****************************** ...
- .net 通过反射实现两个相同结构实体类的转换
public static T2 CopyToModel<T1, T2>(T1 source) { T2 model = default(T2); PropertyInfo[] pi = ...
- .Net Core NPOI读取Excel 并转为数据实体类
创建应用程序 这里直接创建Console程序 引用NPOI的NuGet包 PM> Install-Package NPOI -Version 2.5.1 直接Nuget包管理器添加 导入Exce ...
- 转 利用java反射实现两个具有相同属性bean赋值
package com.dobn.bdgcgl.utils; import java.lang.reflect.Field; import java.lang.reflect.Method; publ ...
- Android利用反射机制为实体类属性赋值
在做android项目时,有时会遇到从网络上获取json类型数据,赋值给实体类,实体类属性少可以一个一个的赋值,如果实体类有很多属性,赋值可能就要耗很长的功夫了,幸好Java给我们提供了反射机制.下面 ...
- 运用Mono.Cecil 反射读取.NET程序集元数据
CLR自带的反射机智和API可以很轻松的读取.NET程序集信息,但是不能对程序集进行修改.CLR提供的是只读的API,但是开源项目Mono.Cecil不仅仅可以读取.NET程序集的元数据,还可以进行修 ...
- SqlHelper简单实现(通过Expression和反射)1.引言
之前老大说要改变代码中充斥着各种Select的Sql语句字符串的情况,让我尝试着做一个简单的SqlHelper,要具有以下功能: 1.不要在业务代码中暴露DataTable或者DataSet类型: 2 ...
- Java通过反射读取泛型
1.在这里有必要先提一句关于javabean,建议有一个构造器,而不是必须要写的,这是一个良好的习惯. 这样做肯定是有好处的,如果你的一个类写了带参的构造方法,而没有写空的构造方法,那么,如有有一个类 ...
- 利用c#反射实现实体类生成以及数据获取与赋值
转:http://hi.baidu.com/xyd21c/item/391da2fc8fb351c10dd1c8b8 原有的实体类成员逐个赋值与获取的方法弊端: 1.每次对实体类属性进行赋值时,都要检 ...
随机推荐
- STL deque容器
deque - 双向队列 1.队列的基本知识 队列的基本特性就是先进先出(FIFO),也就是第一个进去的元素第一个出来.即队列就是一个只允许在一端进行插入,在另一端进行删除操作的线性表.Queue接口 ...
- 文心一言 VS 讯飞星火 VS chatgpt (170)-- 算法导论13.2 3题
三.用go语言,设在图 13-2 左边一棵树中,a.b和c 分别为子树a.β和γ中的任意结点.当结点 x 左旋之后,a.b和c 的深度会如何变化? 文心一言: 在二叉树中,左旋操作是改变节点的子节点顺 ...
- libGDX游戏开发之按轨迹移动(十一)
libGDX游戏开发之运动轨迹绘制(十一) libGDX系列,游戏开发有unity3D巴拉巴拉的,为啥还用java开发?因为我是Java程序员emm-国内用libgdx比较少,多数情况需要去官网和go ...
- Vue接入谷歌广告(Google Adsense)
1.注册账户 首先你要拥有一个google账号,点击注册谷歌账号,点击个人账号根据提示一步一步来即可注册成功.(当然你需要魔法才可以正常访问谷歌服务) 2.补充账户信息,申请广告授权 点击进入Goog ...
- Swagger系列:Spring Boot 2.x集成Spring Doc(Swagger 3.0)
目录 一.简介 1.SpringFox工具(不推荐) 2.SpringDoc工具(推荐) 二.集成 1.环境 1. 引入Maven依赖 2.配置SpringDocConfig(配置类方式) 3.配置S ...
- 在Mac上打开Emoji键盘 ⌨️
因为想要输入Emoji字符,以前总上到网上搜,如 emojipedia.org ,然后复制.最近,输入Emoji有点多,就想查查有没有什么简便方法. 果然有,我用的是macOS,只要按下键盘上的 co ...
- maven 实现pb的实时编译
<properties> <protobuf.version>3.15.7</protobuf.version></properties> <ex ...
- 第九部分_Shell脚本之case语句
case语句 关键词:确认过眼神,你是对的人 case语句为多重匹配语句 如果匹配成功,执行相匹配的命令 1. 语法结构 说明:pattern表示需要匹配的模式 case var in #定义变量;v ...
- GaussDB CN服务异常实例分析
摘要:先通过OPS确认节点状态是否已经恢复,或登录后台执行cm_ctl query -Cv确认集群是否已经Normal. 本文分享自华为云社区<[实例状态]GaussDB CN服务异常>, ...
- 云图说 | 华为云医疗智能体智联大健康:AI医学影像
摘要:华为云医疗智能体面向医学影像领域,提供影像智能标注.算法开发和AI辅助诊断服务. 本文分享自华为云社区<[云图说]第208期 医疗智能体 智联大健康:AI医学影像>,原文作者:阅识风 ...