SqlSugar/Src/Asp.Net/SqlSugar/Abstract/DbBindProvider/IDataReaderEntityBuilder.cs

335 lines
19 KiB
C#
Raw Normal View History

2017-01-07 21:54:51 +08:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Reflection;
using System.Reflection.Emit;
2017-07-09 18:14:33 +08:00
using System.Text.RegularExpressions;
2017-01-07 21:54:51 +08:00
namespace SqlSugar
{
2017-04-23 14:48:57 +08:00
///<summary>
/// ** descriptionIDataReader Entity Builder
/// ** authorsunkaixuan
/// ** date2017/4/2
/// ** qq:610262374
/// </summary>
2017-04-23 02:57:59 +08:00
public partial class IDataReaderEntityBuilder<T>
2017-01-07 21:54:51 +08:00
{
2017-05-28 18:49:49 +08:00
#region Properies
2017-04-24 00:56:18 +08:00
private List<string> ReaderKeys { get; set; }
2017-05-28 18:49:49 +08:00
#endregion
#region Fields
2019-05-11 14:39:00 +08:00
private SqlSugarProvider Context = null;
2017-06-19 01:51:52 +08:00
private IDataReaderEntityBuilder<T> DynamicBuilder;
private IDataRecord DataRecord;
2017-01-07 21:54:51 +08:00
private static readonly MethodInfo isDBNullMethod = typeof(IDataRecord).GetMethod("IsDBNull", new Type[] { typeof(int) });
private static readonly MethodInfo getValueMethod = typeof(IDataRecord).GetMethod("get_Item", new Type[] { typeof(int) });
private static readonly MethodInfo getBoolean = typeof(IDataRecord).GetMethod("GetBoolean", new Type[] { typeof(int) });
private static readonly MethodInfo getByte = typeof(IDataRecord).GetMethod("GetByte", new Type[] { typeof(int) });
private static readonly MethodInfo getDateTime = typeof(IDataRecord).GetMethod("GetDateTime", new Type[] { typeof(int) });
private static readonly MethodInfo getDecimal = typeof(IDataRecord).GetMethod("GetDecimal", new Type[] { typeof(int) });
private static readonly MethodInfo getDouble = typeof(IDataRecord).GetMethod("GetDouble", new Type[] { typeof(int) });
private static readonly MethodInfo getFloat = typeof(IDataRecord).GetMethod("GetFloat", new Type[] { typeof(int) });
private static readonly MethodInfo getGuid = typeof(IDataRecord).GetMethod("GetGuid", new Type[] { typeof(int) });
private static readonly MethodInfo getInt16 = typeof(IDataRecord).GetMethod("GetInt16", new Type[] { typeof(int) });
private static readonly MethodInfo getInt32 = typeof(IDataRecord).GetMethod("GetInt32", new Type[] { typeof(int) });
private static readonly MethodInfo getInt64 = typeof(IDataRecord).GetMethod("GetInt64", new Type[] { typeof(int) });
private static readonly MethodInfo getString = typeof(IDataRecord).GetMethod("GetString", new Type[] { typeof(int) });
2017-09-20 12:44:10 +08:00
private static readonly MethodInfo getdatetimeoffset = typeof(IDataRecordExtensions).GetMethod("Getdatetimeoffset");
private static readonly MethodInfo getdatetimeoffsetDate = typeof(IDataRecordExtensions).GetMethod("GetdatetimeoffsetDate");
2017-06-25 23:42:53 +08:00
private static readonly MethodInfo getStringGuid = typeof(IDataRecordExtensions).GetMethod("GetStringGuid");
private static readonly MethodInfo getConvertStringGuid = typeof(IDataRecordExtensions).GetMethod("GetConvertStringGuid");
2017-06-04 19:22:05 +08:00
private static readonly MethodInfo getEnum = typeof(IDataRecordExtensions).GetMethod("GetEnum");
2017-06-07 14:25:33 +08:00
private static readonly MethodInfo getConvertString = typeof(IDataRecordExtensions).GetMethod("GetConvertString");
2017-01-07 21:54:51 +08:00
private static readonly MethodInfo getConvertFloat = typeof(IDataRecordExtensions).GetMethod("GetConvertFloat");
private static readonly MethodInfo getConvertBoolean = typeof(IDataRecordExtensions).GetMethod("GetConvertBoolean");
private static readonly MethodInfo getConvertByte = typeof(IDataRecordExtensions).GetMethod("GetConvertByte");
private static readonly MethodInfo getConvertChar = typeof(IDataRecordExtensions).GetMethod("GetConvertChar");
private static readonly MethodInfo getConvertDateTime = typeof(IDataRecordExtensions).GetMethod("GetConvertDateTime");
2018-04-08 16:31:27 +08:00
private static readonly MethodInfo getConvertTime = typeof(IDataRecordExtensions).GetMethod("GetConvertTime");
private static readonly MethodInfo getTime = typeof(IDataRecordExtensions).GetMethod("GetTime");
2017-01-07 21:54:51 +08:00
private static readonly MethodInfo getConvertDecimal = typeof(IDataRecordExtensions).GetMethod("GetConvertDecimal");
private static readonly MethodInfo getConvertDouble = typeof(IDataRecordExtensions).GetMethod("GetConvertDouble");
2018-11-26 00:13:18 +08:00
private static readonly MethodInfo getConvertDoubleToFloat = typeof(IDataRecordExtensions).GetMethod("GetConvertDoubleToFloat");
2017-01-07 21:54:51 +08:00
private static readonly MethodInfo getConvertGuid = typeof(IDataRecordExtensions).GetMethod("GetConvertGuid");
private static readonly MethodInfo getConvertInt16 = typeof(IDataRecordExtensions).GetMethod("GetConvertInt16");
private static readonly MethodInfo getConvertInt32 = typeof(IDataRecordExtensions).GetMethod("GetConvertInt32");
2017-07-11 22:06:05 +08:00
private static readonly MethodInfo getConvertInt64 = typeof(IDataRecordExtensions).GetMethod("GetConvetInt64");
2017-01-07 21:54:51 +08:00
private static readonly MethodInfo getConvertEnum_Null = typeof(IDataRecordExtensions).GetMethod("GetConvertEnum_Null");
2017-09-20 12:44:10 +08:00
private static readonly MethodInfo getConvertdatetimeoffset = typeof(IDataRecordExtensions).GetMethod("GetConvertdatetimeoffset");
private static readonly MethodInfo getConvertdatetimeoffsetDate = typeof(IDataRecordExtensions).GetMethod("GetConvertdatetimeoffsetDate");
2017-01-07 21:54:51 +08:00
private static readonly MethodInfo getOtherNull = typeof(IDataRecordExtensions).GetMethod("GetOtherNull");
private static readonly MethodInfo getOther = typeof(IDataRecordExtensions).GetMethod("GetOther");
2019-05-16 20:25:11 +08:00
private static readonly MethodInfo getJson = typeof(IDataRecordExtensions).GetMethod("GetJson");
2017-07-09 19:12:41 +08:00
private static readonly MethodInfo getSqliteTypeNull = typeof(IDataRecordExtensions).GetMethod("GetSqliteTypeNull");
private static readonly MethodInfo getSqliteType = typeof(IDataRecordExtensions).GetMethod("GetSqliteType");
2019-05-11 14:39:00 +08:00
private static readonly MethodInfo getEntity = typeof(IDataRecordExtensions).GetMethod("GetEntity", new Type[] { typeof(SqlSugarProvider) });
2017-09-20 12:44:10 +08:00
2017-01-07 21:54:51 +08:00
private delegate T Load(IDataRecord dataRecord);
private Load handler;
#endregion
2017-06-19 01:51:52 +08:00
#region Constructor
private IDataReaderEntityBuilder()
{
}
2019-05-11 14:39:00 +08:00
public IDataReaderEntityBuilder(SqlSugarProvider context, IDataRecord dataRecord,List<string> fieldNames)
2017-06-19 01:51:52 +08:00
{
this.Context = context;
this.DataRecord = dataRecord;
this.DynamicBuilder = new IDataReaderEntityBuilder<T>();
2017-11-23 16:19:33 +08:00
this.ReaderKeys = fieldNames;
2017-06-19 01:51:52 +08:00
}
#endregion
2017-05-28 18:49:49 +08:00
#region Public methods
2017-01-07 21:54:51 +08:00
public T Build(IDataRecord dataRecord)
{
return handler(dataRecord);
}
2017-04-23 14:30:42 +08:00
public IDataReaderEntityBuilder<T> CreateBuilder(Type type)
2017-01-07 21:54:51 +08:00
{
2017-04-23 14:30:42 +08:00
DynamicMethod method = new DynamicMethod("SqlSugarEntity", type,
2017-01-07 21:54:51 +08:00
new Type[] { typeof(IDataRecord) }, type, true);
ILGenerator generator = method.GetILGenerator();
LocalBuilder result = generator.DeclareLocal(type);
generator.Emit(OpCodes.Newobj, type.GetConstructor(Type.EmptyTypes));
generator.Emit(OpCodes.Stloc, result);
2019-05-16 17:40:55 +08:00
this.Context.InitMppingInfo(type);
var columnInfos = this.Context.EntityMaintenance.GetEntityInfo(type).Columns;
foreach (var columnInfo in columnInfos)
2017-01-07 21:54:51 +08:00
{
2019-05-16 17:40:55 +08:00
string fileName = columnInfo.DbColumnName ?? columnInfo.PropertyName;
if (columnInfo.IsIgnore)
2017-04-23 14:07:04 +08:00
{
continue;
}
2019-05-16 17:40:55 +08:00
if (columnInfo != null && columnInfo.PropertyInfo.GetSetMethod() != null)
2017-01-07 21:54:51 +08:00
{
2019-05-16 17:40:55 +08:00
if (columnInfo.PropertyInfo.PropertyType.IsClass() && columnInfo.PropertyInfo.PropertyType != UtilConstants.ByteArrayType && columnInfo.PropertyInfo.PropertyType != UtilConstants.ObjType)
2017-04-23 14:07:04 +08:00
{
2019-05-16 19:38:56 +08:00
if (this.ReaderKeys.Any(it => it.Equals(fileName, StringComparison.CurrentCultureIgnoreCase)))
{
BindClass(generator, result, columnInfo,ReaderKeys.First(it => it.Equals(fileName, StringComparison.CurrentCultureIgnoreCase)));
}
2017-04-23 14:07:04 +08:00
}
else
{
2017-04-24 00:56:18 +08:00
if (this.ReaderKeys.Any(it => it.Equals(fileName, StringComparison.CurrentCultureIgnoreCase)))
{
2019-05-16 17:47:38 +08:00
BindField(generator, result, columnInfo, ReaderKeys.First(it => it.Equals(fileName, StringComparison.CurrentCultureIgnoreCase)));
2017-04-24 00:56:18 +08:00
}
2017-04-23 14:07:04 +08:00
}
2017-01-07 21:54:51 +08:00
}
}
generator.Emit(OpCodes.Ldloc, result);
generator.Emit(OpCodes.Ret);
2017-04-23 14:07:04 +08:00
DynamicBuilder.handler = (Load)method.CreateDelegate(typeof(Load));
return DynamicBuilder;
2017-06-07 02:12:04 +08:00
}
2017-11-23 16:07:02 +08:00
2017-05-28 18:49:49 +08:00
#endregion
#region Private methods
2019-05-16 19:38:56 +08:00
private void BindClass(ILGenerator generator, LocalBuilder result, EntityColumnInfo columnInfo, string fieldName)
2017-04-23 14:07:04 +08:00
{
2019-05-16 19:38:56 +08:00
if (columnInfo.IsJson)
{
2019-05-16 20:25:11 +08:00
MethodInfo jsonMethod = getJson.MakeGenericMethod(columnInfo.PropertyInfo.PropertyType);
2019-05-16 19:38:56 +08:00
int i = DataRecord.GetOrdinal(fieldName);
Label endIfLabel = generator.DefineLabel();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldc_I4, i);
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, i);
2019-05-16 20:25:11 +08:00
generator.Emit(OpCodes.Call, jsonMethod);
2019-05-16 19:38:56 +08:00
generator.Emit(OpCodes.Callvirt, columnInfo.PropertyInfo.GetSetMethod());
generator.MarkLabel(endIfLabel);
}
2017-04-23 14:07:04 +08:00
}
2019-05-16 17:47:38 +08:00
private void BindField(ILGenerator generator, LocalBuilder result, EntityColumnInfo columnInfo, string fieldName)
2017-04-23 14:07:04 +08:00
{
2019-05-16 17:42:30 +08:00
int i = DataRecord.GetOrdinal(fieldName);
2017-04-23 14:07:04 +08:00
Label endIfLabel = generator.DefineLabel();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldc_I4, i);
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, i);
2019-05-16 17:47:38 +08:00
BindMethod(generator, columnInfo, i);
generator.Emit(OpCodes.Callvirt, columnInfo.PropertyInfo.GetSetMethod());
2017-04-23 14:07:04 +08:00
generator.MarkLabel(endIfLabel);
2017-04-23 02:57:59 +08:00
}
2019-05-16 17:47:38 +08:00
private void BindMethod(ILGenerator generator, EntityColumnInfo columnInfo, int ordinal)
2017-01-07 21:54:51 +08:00
{
2017-06-07 02:12:04 +08:00
IDbBind bind = Context.Ado.DbBind;
bool isNullableType = false;
MethodInfo method = null;
2019-05-16 17:47:38 +08:00
Type bindPropertyType = UtilMethods.GetUnderType(columnInfo.PropertyInfo, ref isNullableType);
2017-10-10 14:41:08 +08:00
string dbTypeName = UtilMethods.GetParenthesesValue(DataRecord.GetDataTypeName(ordinal));
2018-04-21 14:26:53 +08:00
if (dbTypeName.IsNullOrEmpty()) {
dbTypeName = bindPropertyType.Name;
}
2019-05-16 17:47:38 +08:00
string propertyName = columnInfo.PropertyName;
2017-06-07 02:12:04 +08:00
string validPropertyName = bind.GetPropertyTypeName(dbTypeName);
validPropertyName = validPropertyName == "byte[]" ? "byteArray" : validPropertyName;
CSharpDataType validPropertyType = (CSharpDataType)Enum.Parse(typeof(CSharpDataType), validPropertyName);
2017-07-09 19:12:41 +08:00
#region Sqlite Logic
if (this.Context.CurrentConnectionConfig.DbType == DbType.Sqlite)
{
2017-07-10 00:55:18 +08:00
if (bindPropertyType.IsEnum())
{
method = isNullableType ? getConvertEnum_Null.MakeGenericMethod(bindPropertyType) : getEnum.MakeGenericMethod(bindPropertyType);
}
2017-08-25 22:22:12 +08:00
else if (bindPropertyType == UtilConstants.IntType)
2017-07-09 21:11:32 +08:00
{
method = isNullableType ? getConvertInt32 : getInt32;
}
2019-04-20 20:26:21 +08:00
else if (bindPropertyType == UtilConstants.ByteType)
{
method = isNullableType ? getConvertByte : getByte;
}
2017-08-25 22:22:12 +08:00
else if (bindPropertyType == UtilConstants.StringType)
2017-07-09 21:11:32 +08:00
{
method = getString;
}
2017-08-25 22:22:12 +08:00
else if (bindPropertyType == UtilConstants.ByteArrayType)
2017-07-09 21:11:32 +08:00
{
method = getValueMethod;
generator.Emit(OpCodes.Call, method);
2019-05-16 17:47:38 +08:00
generator.Emit(OpCodes.Unbox_Any, columnInfo.PropertyInfo.PropertyType);
2017-07-09 21:11:32 +08:00
return;
}
else
{
method = isNullableType ? getSqliteTypeNull.MakeGenericMethod(bindPropertyType) : getSqliteType.MakeGenericMethod(bindPropertyType);
}
2017-07-09 19:12:41 +08:00
generator.Emit(OpCodes.Call, method);
return;
};
#endregion
#region Common Database Logic
2017-06-07 02:12:04 +08:00
string bindProperyTypeName = bindPropertyType.Name.ToLower();
2017-07-01 13:10:36 +08:00
bool isEnum = bindPropertyType.IsEnum();
2017-06-07 02:12:04 +08:00
if (isEnum) { validPropertyType = CSharpDataType.@enum; }
switch (validPropertyType)
2017-01-07 21:54:51 +08:00
{
2017-06-07 02:12:04 +08:00
case CSharpDataType.@int:
CheckType(bind.IntThrow, bindProperyTypeName, validPropertyName, propertyName);
2017-07-11 22:06:05 +08:00
if (bindProperyTypeName.IsContainsIn("int", "int32"))
2017-06-09 18:55:45 +08:00
method = isNullableType ? getConvertInt32 : getInt32;
2017-07-11 22:06:05 +08:00
if (bindProperyTypeName.IsContainsIn("int64"))
2018-02-01 16:19:00 +08:00
method = isNullableType ? getConvertInt64 : getInt64;
2017-07-17 12:24:29 +08:00
if (bindProperyTypeName.IsContainsIn("byte"))
method = isNullableType ? getConvertByte : getByte;
if (bindProperyTypeName.IsContainsIn("int16"))
method = isNullableType ? getConvertInt16 : getInt16;
2017-06-07 02:12:04 +08:00
break;
case CSharpDataType.@bool:
if (bindProperyTypeName == "bool" || bindProperyTypeName == "boolean")
method = isNullableType ? getConvertBoolean : getBoolean;
break;
case CSharpDataType.@string:
CheckType(bind.StringThrow, bindProperyTypeName, validPropertyName, propertyName);
method = getString;
2017-07-09 19:12:41 +08:00
if (bindProperyTypeName == "guid")
{
2017-10-10 14:41:08 +08:00
method = isNullableType ? getConvertStringGuid : getStringGuid;
2017-06-25 23:42:53 +08:00
}
2017-06-07 02:12:04 +08:00
break;
case CSharpDataType.DateTime:
CheckType(bind.DateThrow, bindProperyTypeName, validPropertyName, propertyName);
if (bindProperyTypeName == "datetime")
method = isNullableType ? getConvertDateTime : getDateTime;
2019-03-28 22:02:27 +08:00
if (bindProperyTypeName == "datetime"&&dbTypeName.ToLower() == "time")
2018-04-08 16:31:27 +08:00
method = isNullableType ? getConvertTime : getTime;
2017-06-07 02:12:04 +08:00
break;
case CSharpDataType.@decimal:
CheckType(bind.DecimalThrow, bindProperyTypeName, validPropertyName, propertyName);
if (bindProperyTypeName == "decimal")
method = isNullableType ? getConvertDecimal : getDecimal;
break;
2017-06-17 00:27:47 +08:00
case CSharpDataType.@float:
2017-06-07 02:12:04 +08:00
case CSharpDataType.@double:
CheckType(bind.DoubleThrow, bindProperyTypeName, validPropertyName, propertyName);
2017-11-23 14:55:12 +08:00
if (bindProperyTypeName.IsIn( "double", "single")&&dbTypeName!="real")
2017-06-07 02:12:04 +08:00
method = isNullableType ? getConvertDouble : getDouble;
2017-11-23 14:55:12 +08:00
else
method = isNullableType ? getConvertFloat : getFloat;
2018-11-27 00:55:38 +08:00
if (dbTypeName.Equals("float",StringComparison.CurrentCultureIgnoreCase) && isNullableType && bindProperyTypeName.Equals("single",StringComparison.CurrentCultureIgnoreCase)) {
2018-11-26 00:13:18 +08:00
method = getConvertDoubleToFloat;
}
2017-06-07 02:12:04 +08:00
break;
case CSharpDataType.Guid:
CheckType(bind.GuidThrow, bindProperyTypeName, validPropertyName, propertyName);
if (bindProperyTypeName == "guid")
2017-09-07 19:46:15 +08:00
method = isNullableType ? getConvertGuid : getGuid;
2017-06-07 02:12:04 +08:00
break;
case CSharpDataType.@byte:
2017-07-25 13:54:01 +08:00
if (bindProperyTypeName == "byte")
method = isNullableType ? getConvertByte : getByte;
2017-06-07 02:12:04 +08:00
break;
case CSharpDataType.@enum:
method = isNullableType ? getConvertEnum_Null.MakeGenericMethod(bindPropertyType) : getEnum.MakeGenericMethod(bindPropertyType);
break;
case CSharpDataType.@short:
CheckType(bind.ShortThrow, bindProperyTypeName, validPropertyName, propertyName);
2017-06-25 05:33:39 +08:00
if (bindProperyTypeName == "int16" || bindProperyTypeName == "short")
2017-06-07 02:12:04 +08:00
method = isNullableType ? getConvertInt16 : getInt16;
break;
case CSharpDataType.@long:
2017-06-25 05:33:39 +08:00
if (bindProperyTypeName == "int64" || bindProperyTypeName == "long")
2017-07-11 22:06:05 +08:00
method = isNullableType ? getConvertInt64 : getInt64;
2017-06-07 02:12:04 +08:00
break;
2017-09-20 12:44:10 +08:00
case CSharpDataType.DateTimeOffset:
2017-10-10 14:41:08 +08:00
method = isNullableType ? getConvertdatetimeoffset : getdatetimeoffset;
2017-09-20 12:44:10 +08:00
if (bindProperyTypeName == "datetime")
method = isNullableType ? getConvertdatetimeoffsetDate : getdatetimeoffsetDate;
break;
2017-06-07 02:12:04 +08:00
default:
method = getValueMethod;
break;
2017-01-07 21:54:51 +08:00
}
2017-08-25 22:22:12 +08:00
if (method == null && bindPropertyType == UtilConstants.StringType)
2017-07-09 19:12:41 +08:00
{
2017-06-07 14:25:33 +08:00
method = getConvertString;
2017-06-07 13:46:45 +08:00
}
2017-10-10 14:41:08 +08:00
if (bindPropertyType == UtilConstants.ObjType)
{
2017-10-10 14:27:40 +08:00
method = getValueMethod;
}
2017-06-07 02:12:04 +08:00
if (method == null)
2017-07-09 19:12:41 +08:00
method = isNullableType ? getOtherNull.MakeGenericMethod(bindPropertyType) : getOther.MakeGenericMethod(bindPropertyType);
2017-06-07 02:12:04 +08:00
generator.Emit(OpCodes.Call, method);
if (method == getValueMethod)
2017-01-07 21:54:51 +08:00
{
2019-05-16 17:47:38 +08:00
generator.Emit(OpCodes.Unbox_Any, columnInfo.PropertyInfo.PropertyType);
2017-07-09 21:11:32 +08:00
}
2017-07-09 19:12:41 +08:00
#endregion
2017-04-23 02:57:59 +08:00
}
2017-06-07 02:12:04 +08:00
private void CheckType(List<string> invalidTypes, string bindProperyTypeName, string validPropertyType, string propertyName)
2017-04-23 14:30:42 +08:00
{
2017-06-07 02:12:04 +08:00
var isAny = invalidTypes.Contains(bindProperyTypeName);
2017-04-23 14:30:42 +08:00
if (isAny)
{
2018-12-07 16:32:42 +08:00
throw new SqlSugarException(string.Format("{0} can't convert {1} to {2}", propertyName, validPropertyType, bindProperyTypeName));
2017-04-23 14:30:42 +08:00
}
2017-06-07 02:12:04 +08:00
}
2017-05-28 18:49:49 +08:00
#endregion
2017-01-07 21:54:51 +08:00
}
}