使用EMIT将DataTable转为实体列表

public static class EntityConverter
{
	public static Dictionary<string, Func<DataRow, object>> handleDict =
		new Dictionary<string, Func<DataRow, object>>();
	public static Dictionary<string, Func<IDataRecord, List<string>, object>> DataRecordHandler =
		new Dictionary<string, Func<IDataRecord, List<string>, object>>();


	/// <summary>
	/// 将DataTable转为对象列表
	/// </summary>
	/// <typeparam name="T"></typeparam>
	/// <param name="dt"></param>
	/// <returns></returns>
	public static List<T> ToList<T>(this DataTable dt, bool bIsDispose) where T : class, new()
	{
		List<T> list = new List<T>();
		if (dt == null || dt.Rows.Count == 0)
			return list;

		Func<DataRow, object> handler = null;
		string key = dt.TableName + "_" + typeof(T).Name;
		if (handleDict.ContainsKey(key))
		{
			handler = (Func<DataRow, object>)handleDict[key];
		}
		else
		{
			DataTableEntityBuilder<T> eblist = DataTableEntityBuilder<T>.CreateBuilderOfDataRow();
			handler = eblist.DataRowHandler;
			handleDict.Add(key, handler);
		}
		try
		{
			foreach (DataRow info in dt.Rows)
			{
				list.Add((T)handler(info));
			}
		}
		finally
		{
			if (bIsDispose)
			{
				dt.Dispose();
				dt = null;
			}
		}
		return list;
	}


	/// <summary>
	/// 将DataTable转为对象列表
	/// </summary>
	/// <typeparam name="T"></typeparam>
	/// <param name="dt"></param>
	/// <returns></returns>
	public static T ToEntity<T>(this DataRow dr) where T : class, new()
	{

		if (dr == null)
			return null;

		Func<DataRow, object> handler = null;
		string key = dr.Table.TableName + "_" + typeof(T).Name;
		if (handleDict.ContainsKey(key))
		{
			handler = (Func<DataRow, object>)handleDict[key];
		}
		else
		{
			DataTableEntityBuilder<T> eblist = DataTableEntityBuilder<T>.CreateBuilderOfDataRow();
			handler = eblist.DataRowHandler;
			handleDict.Add(key, handler);
		}
		try
		{
			return (T)handler(dr);
		}
		finally
		{
		}
	}

	/// <summary>
	/// 将DataTable转为对象列表
	/// </summary>
	/// <typeparam name="T"></typeparam>
	/// <param name="dt"></param>
	/// <returns></returns>
	public static List<T> ToList<T>(this IDataReader dr, bool bIsDispose) where T : class, new()
	{
		List<T> list = new List<T>();
		if (dr == null)
			return list;
		Func<IDataRecord, List<string>, object> handler = null;
		string key = "DataReader_" + typeof(T).Name;
		if (DataRecordHandler.ContainsKey(key))
		{
			handler = (Func<IDataRecord, List<string>, object>)DataRecordHandler[key];
		}
		else
		{
			DataTableEntityBuilder<T> eblist = DataTableEntityBuilder<T>.CreateBuilderOfDataRecord();
			handler = eblist.DataRecordHandler;
			DataRecordHandler.Add(key, handler);
		}
		List<string> cols = new List<string>();
		for (int i = 0; i < dr.FieldCount; i++)
		{
			cols.Add(dr.GetName(i).ToLower());
		}
		while (dr.Read())
		{
			list.Add((T)handler(dr, cols));
		}
		return list;
	}

	/// <summary>
	/// 使用EMIT
	/// </summary>
	/// <typeparam name="Entity"></typeparam>
	public class DataTableEntityBuilder<Entity>
	{
		//数据类型和对应的强制转换方法的methodinfo,供实体属性赋值时调用
		private static Dictionary<Type, MethodInfo> ConvertMethods = new Dictionary<Type, MethodInfo>()
	   {
		   {typeof(int),typeof(Convert).GetMethod("ToInt32",new Type[]{typeof(object)})},
		   {typeof(Int16),typeof(Convert).GetMethod("ToInt16",new Type[]{typeof(object)})},
		   {typeof(Int64),typeof(Convert).GetMethod("ToInt64",new Type[]{typeof(object)})},
		   {typeof(DateTime),typeof(Convert).GetMethod("ToDateTime",new Type[]{typeof(object)})},
		   {typeof(decimal),typeof(Convert).GetMethod("ToDecimal",new Type[]{typeof(object)})},
		   {typeof(Double),typeof(Convert).GetMethod("ToDouble",new Type[]{typeof(object)})},
		   {typeof(Boolean),typeof(Convert).GetMethod("ToBoolean",new Type[]{typeof(object)})},
		   {typeof(string),typeof(Convert).GetMethod("ToString",new Type[]{typeof(object)})},
		   //{typeof(Nullable<int>),typeof(Convert).GetMethod("ToInt32",new Type[]{typeof(object)})},
		   //{typeof(Nullable<Int16>),typeof(Convert).GetMethod("ToInt16",new Type[]{typeof(object)})},
		   //{typeof(Nullable<Int64>),typeof(Convert).GetMethod("ToInt64",new Type[]{typeof(object)})},
		   //{typeof(Nullable<DateTime>),typeof(Convert).GetMethod("ToDateTime",new Type[]{typeof(object)})},
		   //{typeof(Nullable<decimal>),typeof(Convert).GetMethod("ToDecimal",new Type[]{typeof(object)})},
		   //{typeof(Nullable<Double>),typeof(Convert).GetMethod("ToDouble",new Type[]{typeof(object)})},
		   //{typeof(Nullable<Boolean>),typeof(Convert).GetMethod("ToBoolean",new Type[]{typeof(object)})},
		   //{typeof(string),typeof(Convert).GetMethod("ToString",new Type[]{typeof(object)})}
	   };

		#region DataRow

		private static readonly MethodInfo getValueMethod = typeof(DataRow).GetMethod("get_Item", new Type[] { typeof(string) });
		private static readonly MethodInfo isDBNullMethod = typeof(DataRow).GetMethod("IsNull", new Type[] { typeof(string) });
		private static readonly MethodInfo getTableMethod = typeof(DataRow).GetMethod("get_Table", new Type[] { });
		private static readonly MethodInfo getColumns = typeof(DataTable).GetMethod("get_Columns", new Type[] { });
		private static readonly MethodInfo Contains = typeof(DataColumnCollection).GetMethod("Contains", new Type[] { typeof(string) });
		public Func<DataRow, object> DataRowHandler { get; set; }

		#endregion

		#region IDataRecord

		private static readonly MethodInfo IndexOf = typeof(List<string>).GetMethod("IndexOf", new Type[] { typeof(string) });
		private static readonly MethodInfo getCount = typeof(List<string>).GetMethod("get_Count", new Type[] { });
		private static readonly MethodInfo IsDBNull = typeof(IDataRecord).GetMethod("IsDBNull", new Type[] { typeof(int) });
		private static readonly MethodInfo getItem = typeof(IDataRecord).GetMethod("get_Item", new Type[] { typeof(int) });

		public Func<IDataRecord, List<string>, object> DataRecordHandler { get; set; }

		#endregion

		private DataTableEntityBuilder() { }

		/// <summary>
		/// 如果DataRow中的列与实体中的不一致,会报错
		/// </summary>
		/// <param name="dataRow"></param>
		/// <returns></returns>
		public static DataTableEntityBuilder<Entity> CreateBuilder(DataRow dataRow)
		{
			DataTableEntityBuilder<Entity> dynamicBuilder = new DataTableEntityBuilder<Entity>();
			DynamicMethod method = new DynamicMethod("DynamicCreateEntity", typeof(Entity), new Type[] { typeof(DataRow) }, typeof(Entity), true);
			ILGenerator generator = method.GetILGenerator();
			LocalBuilder result = generator.DeclareLocal(typeof(Entity));
			generator.Emit(OpCodes.Newobj, typeof(Entity).GetConstructor(Type.EmptyTypes));
			generator.Emit(OpCodes.Stloc, result);

			for (int index = 0; index < dataRow.ItemArray.Length; index++)
			{
				PropertyInfo propertyInfo = typeof(Entity).GetProperty(dataRow.Table.Columns[index].ColumnName);
				Label endIfLabel = generator.DefineLabel();
				if (propertyInfo != null && propertyInfo.GetSetMethod() != null)
				{
					generator.Emit(OpCodes.Ldarg_0);
					generator.Emit(OpCodes.Ldc_I4, index);
					generator.Emit(OpCodes.Callvirt, isDBNullMethod);
					generator.Emit(OpCodes.Brtrue, endIfLabel);
					generator.Emit(OpCodes.Ldloc, result);
					generator.Emit(OpCodes.Ldarg_0);
					generator.Emit(OpCodes.Ldc_I4, index);
					generator.Emit(OpCodes.Callvirt, getValueMethod);
					generator.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType);
					generator.Emit(OpCodes.Callvirt, propertyInfo.GetSetMethod());
					generator.MarkLabel(endIfLabel);
				}
			}
			generator.Emit(OpCodes.Ldloc, result);
			generator.Emit(OpCodes.Ret);
			dynamicBuilder.DataRowHandler = (Func<DataRow, object>)method.CreateDelegate(typeof(Func<DataRow, object>));
			return dynamicBuilder;
		}

		/// <summary>
		/// DataRow转Entity
		/// </summary>
		/// <returns></returns>
		public static DataTableEntityBuilder<Entity> CreateBuilderOfDataRow()
		{
			DataTableEntityBuilder<Entity> dynamicBuilder = new DataTableEntityBuilder<Entity>();
			DynamicMethod method = new DynamicMethod("DataRow2Entity", typeof(Entity), new Type[] { typeof(DataRow) }, typeof(Entity), true);
			ILGenerator generator = method.GetILGenerator();
			// 返回值(如Role对象)
			// T result;
			LocalBuilder result = generator.DeclareLocal(typeof(Entity));
			// result = new T();
			generator.Emit(OpCodes.Newobj, typeof(Entity).GetConstructor(Type.EmptyTypes));
			generator.Emit(OpCodes.Stloc, result);

			foreach (PropertyInfo property in typeof(Entity).GetProperties())
			{
				// if (dr.Table.Columns.Contains(property.Name))
				Label endIfContains = generator.DefineLabel();
				generator.Emit(OpCodes.Ldarg_0);
				generator.Emit(OpCodes.Callvirt, getTableMethod);
				generator.Emit(OpCodes.Callvirt, getColumns);
				generator.Emit(OpCodes.Ldstr, property.Name);
				generator.Emit(OpCodes.Callvirt, Contains);
				// 为false,则到generator.MarkLabel(endIfContains);中的代码不执行
				generator.Emit(OpCodes.Brfalse, endIfContains);

				// if (!dr.IsNull(property.Name))
				Label endIfDBNull = generator.DefineLabel();
				generator.Emit(OpCodes.Ldarg_0);
				generator.Emit(OpCodes.Ldstr, property.Name);
				generator.Emit(OpCodes.Callvirt, isDBNullMethod);
				// 如果dr.IsNull(property.Name)为true,则到generator.MarkLabel(endIfDBNull)间的代码不执行
				generator.Emit(OpCodes.Brtrue, endIfDBNull);

				//generator.Emit(OpCodes.Ldstr, "I'm test");
				//generator.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(String) }));

				generator.Emit(OpCodes.Ldloc, result);
				generator.Emit(OpCodes.Ldarg_0);
				generator.Emit(OpCodes.Ldstr, property.Name);
				generator.Emit(OpCodes.Callvirt, getValueMethod);

				bool bIsNullable = false;
				Type columnType = property.PropertyType;
				if (property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
				{
					bIsNullable = true;
					// If it is NULLABLE, then get the underlying type. eg if "Nullable<int>" then this will return just "int"
					columnType = property.PropertyType.GetGenericArguments()[0];
				}

				var castMethod = typeof(Convert).GetMethod("To" + columnType.Name, new Type[] { typeof(object) });
				if (columnType == typeof(DateTime))
				{
					//generator.Emit(OpCodes.Unbox_Any, columnType);
					//generator.Emit(OpCodes.Callvirt, property.GetSetMethod());
					if (bIsNullable)
					{
						generator.Emit(OpCodes.Call, castMethod);
						generator.Emit(OpCodes.Newobj, property.PropertyType.GetConstructor(new[] { columnType }));
					}
					else
					{
						generator.Emit(OpCodes.Unbox_Any, columnType);
					}
				}
				else
				{
					// 使用下面的方法时,日期类型会出错
					if ((columnType.IsValueType ||
						columnType == typeof(string))
						&& ConvertMethods.ContainsKey(columnType))
					{
						//generator.Emit(OpCodes.Call, ConvertMethods[columnType]);
						generator.Emit(OpCodes.Call, castMethod);
						if (bIsNullable)
						{
							//https://stackoverflow.com/questions/21711255/unboxing-nullable-when-emitting-code-for-a-method-leaves-evaluation-stack-in-an
							generator.Emit(OpCodes.Newobj, property.PropertyType.GetConstructor(new[] { columnType }));
						}
					}
					else
						generator.Emit(OpCodes.Castclass, columnType);
					//generator.Emit(OpCodes.Callvirt, property.GetSetMethod());
				}
				generator.Emit(OpCodes.Callvirt, property.GetSetMethod());

				generator.MarkLabel(endIfDBNull);
				generator.MarkLabel(endIfContains);
			}
			generator.Emit(OpCodes.Ldloc, result);
			generator.Emit(OpCodes.Ret);

			dynamicBuilder.DataRowHandler = (Func<DataRow, object>)method.CreateDelegate(typeof(Func<DataRow, object>));
			return dynamicBuilder;
		}

		/// <summary>
		/// DataReader转Entity
		/// </summary>
		/// <returns></returns>
		public static DataTableEntityBuilder<Entity> CreateBuilderOfDataRecord()
		{
			DataTableEntityBuilder<Entity> dynamicBuilder = new DataTableEntityBuilder<Entity>();
			DynamicMethod method = new DynamicMethod("DataReader2Entity", typeof(Entity), new Type[] { typeof(IDataRecord), typeof(List<string>) }, typeof(Entity), true);
			ILGenerator generator = method.GetILGenerator();
			// 返回值(如Role对象)
			// T result;
			LocalBuilder result = generator.DeclareLocal(typeof(Entity));
			LocalBuilder j = generator.DeclareLocal(typeof(int));
			// result = new T();
			generator.Emit(OpCodes.Newobj, typeof(Entity).GetConstructor(Type.EmptyTypes));
			generator.Emit(OpCodes.Stloc, result);
			foreach (PropertyInfo property in typeof(Entity).GetProperties())
			{
				//int j = cols.IndexOf(property.Name.ToLower());
				generator.Emit(OpCodes.Ldarg_1);
				generator.Emit(OpCodes.Ldstr, property.Name.ToLower());
				generator.Emit(OpCodes.Callvirt, IndexOf);
				generator.Emit(OpCodes.Stloc, j);
				// if (j >= 0)
				Label endIfBlt = generator.DefineLabel();
				generator.Emit(OpCodes.Ldloc_S, j);
				generator.Emit(OpCodes.Ldc_I4_0);
				// 为false,则到generator.MarkLabel(endIfContains); 中的代码不执行
				generator.Emit(OpCodes.Blt_S, endIfBlt);

				// if (j < cols.Count)
				Label endIfBge = generator.DefineLabel();
				generator.Emit(OpCodes.Ldloc_S, j);
				generator.Emit(OpCodes.Ldarg_1);
				generator.Emit(OpCodes.Callvirt, getCount);
				generator.Emit(OpCodes.Bge_S, endIfBge);

				// if (!dr.IsDBNull(j))
				Label endIfDBNull = generator.DefineLabel();
				generator.Emit(OpCodes.Ldarg_0);
				generator.Emit(OpCodes.Ldloc_S, j);
				generator.Emit(OpCodes.Callvirt, IsDBNull);
				// 如果dr.IsNull(property.Name)为true,则到generator.MarkLabel(endIfDBNull)间的代码不执行
				generator.Emit(OpCodes.Brtrue, endIfDBNull);

				//generator.Emit(OpCodes.Ldstr, "I'm test");
				//generator.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(String) }));

				generator.Emit(OpCodes.Ldloc, result);
				generator.Emit(OpCodes.Ldarg_0);
				generator.Emit(OpCodes.Ldloc_S, j);
				generator.Emit(OpCodes.Callvirt, getItem);
				generator.Emit(OpCodes.Unbox_Any, property.PropertyType);
				generator.Emit(OpCodes.Callvirt, property.GetSetMethod());

				// System.Nullable`1<int32>
				// 使用下面的方法时,日期类型会出错
				//if ((property.PropertyType.IsValueType ||
				//    property.PropertyType == typeof(string))
				//    && ConvertMethods.ContainsKey(property.PropertyType))
				//    generator.Emit(OpCodes.Call, ConvertMethods[property.PropertyType]);
				//else
				//    generator.Emit(OpCodes.Castclass, property.PropertyType);
				//generator.Emit(OpCodes.Callvirt, property.GetSetMethod());

				generator.MarkLabel(endIfDBNull);
				generator.MarkLabel(endIfBge);
				generator.MarkLabel(endIfBlt);
			}
			generator.Emit(OpCodes.Ldloc, result);
			generator.Emit(OpCodes.Ret);

			dynamicBuilder.DataRecordHandler = (Func<IDataRecord, List<string>, object>)method.CreateDelegate(typeof(Func<IDataRecord, List<string>, object>));
			return dynamicBuilder;
		}
	}

	/// <summary>
	/// 实体转DataTable
	/// </summary>
	/// <typeparam name="T"></typeparam>
	/// <param name="list"></param>
	/// <returns></returns>
	public static DataTable ToDataTable<T>(this IList<T> list)
	{
		Type elementType = typeof(T);
		var t = new DataTable();

		elementType.GetProperties().ToList().ForEach(propInfo => t.Columns.Add(propInfo.Name, Nullable.GetUnderlyingType(propInfo.PropertyType) ?? propInfo.PropertyType));
		foreach (T item in list)
		{
			var row = t.NewRow();
			elementType.GetProperties().ToList().ForEach(propInfo => row[propInfo.Name] = propInfo.GetValue(item, null) ?? DBNull.Value);
			t.Rows.Add(row);
		}
		return t;
	}

	/// <summary>
	/// 实体转DataTable
	/// </summary>
	/// <typeparam name="T"></typeparam>
	/// <param name="list"></param>
	/// <param name="dt"></param>
	public static void ToDataTable<T>(this IList<T> list, DataTable dt)
	{
		Type elementType = typeof(T);
		foreach (T item in list)
		{
			var row = dt.NewRow();
			elementType.GetProperties().ToList().ForEach(propInfo =>
			{
				if (dt.Columns.Contains(propInfo.Name))
					row[propInfo.Name] = propInfo.GetValue(item, null) ?? DBNull.Value;
			});
			dt.Rows.Add(row);
		}
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue 3中使用emit的方式与Vue 2是相同的。emit是Vue的一个实例方法,用于在子组件中触发父组件定义的事件。通过emit,子组件可以向父组件传递消息或数据。具体使用方式如下: 1. 在父组件中定义一个方法,用来处理子组件触发的事件。可以在methods选项中定义该方法,也可以使用Vue组件的emits选项来声明事件。 2. 在子组件中,通过调用this.$emit(eventName, payload)来触发父组件的事件。其中eventName是父组件定义的事件名称,payload是要传递给父组件的数据。 3. 在父组件的模板中,通过在子组件标签上使用v-on指令来监听子组件的事件。可以使用@eventName="handler"或v-on:eventName="handler"来监听事件,其中eventName是父组件定义的事件名称,handler是处理该事件的方法。 需要注意的是,父组件和子组件之间通过props传递数据,而通过emit传递事件。这样做的目的是保持父组件的数据单向流动,符合Vue的响应式数据流的思想。 综上所述,使用emit可以在Vue 3中实现子组件向父组件传递消息或数据的功能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [使用 Vue3 开发了四个月,回顾 emit 的用法](https://blog.csdn.net/fang_my/article/details/127759757)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值