IDataReaderEntityBuilder.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Data;
  6. using System.Reflection;
  7. using System.Reflection.Emit;
  8. using System.Text.RegularExpressions;
  9. using System.Xml.Linq;
  10. namespace SqlSugar
  11. {
  12. ///<summary>
  13. /// ** description:IDataReader Entity Builder
  14. /// ** author:sunkaixuan
  15. /// ** date:2017/4/2
  16. /// ** qq:610262374
  17. /// </summary>
  18. public partial class IDataReaderEntityBuilder<T>
  19. {
  20. #region Properies
  21. private List<string> ReaderKeys { get; set; }
  22. #endregion
  23. #region Fields
  24. private SqlSugarProvider Context = null;
  25. private IDataReaderEntityBuilder<T> DynamicBuilder;
  26. private IDataRecord DataRecord;
  27. private static readonly MethodInfo isDBNullMethod = typeof(IDataRecord).GetMethod("IsDBNull", new Type[] { typeof(int) });
  28. private static readonly MethodInfo getBoolean = typeof(IDataRecord).GetMethod("GetBoolean", new Type[] { typeof(int) });
  29. private static readonly MethodInfo getByte = typeof(IDataRecord).GetMethod("GetByte", new Type[] { typeof(int) });
  30. private static readonly MethodInfo getDateTime = typeof(IDataRecord).GetMethod("GetDateTime", new Type[] { typeof(int) });
  31. private static readonly MethodInfo getDecimal = typeof(IDataRecord).GetMethod("GetDecimal", new Type[] { typeof(int) });
  32. private static readonly MethodInfo getDouble = typeof(IDataRecord).GetMethod("GetDouble", new Type[] { typeof(int) });
  33. private static readonly MethodInfo getFloat = typeof(IDataRecord).GetMethod("GetFloat", new Type[] { typeof(int) });
  34. private static readonly MethodInfo getGuid = typeof(IDataRecord).GetMethod("GetGuid", new Type[] { typeof(int) });
  35. private static readonly MethodInfo getInt16 = typeof(IDataRecord).GetMethod("GetInt16", new Type[] { typeof(int) });
  36. private static readonly MethodInfo getInt32 = typeof(IDataRecord).GetMethod("GetInt32", new Type[] { typeof(int) });
  37. private static readonly MethodInfo getInt64 = typeof(IDataRecord).GetMethod("GetInt64", new Type[] { typeof(int) });
  38. private static readonly MethodInfo getString = typeof(IDataRecord).GetMethod("GetString", new Type[] { typeof(int) });
  39. //private static readonly MethodInfo getConvertValueMethod = typeof(IDataRecordExtensions).GetMethod("GetConvertValue");
  40. private static readonly MethodInfo getdatetimeoffset = typeof(IDataRecordExtensions).GetMethod("Getdatetimeoffset");
  41. private static readonly MethodInfo getdatetimeoffsetDate = typeof(IDataRecordExtensions).GetMethod("GetdatetimeoffsetDate");
  42. private static readonly MethodInfo getStringGuid = typeof(IDataRecordExtensions).GetMethod("GetStringGuid");
  43. private static readonly MethodInfo getXelement = typeof(IDataRecordExtensions).GetMethod("GetXelement");
  44. private static readonly MethodInfo getConvertStringGuid = typeof(IDataRecordExtensions).GetMethod("GetConvertStringGuid");
  45. private static readonly MethodInfo getEnum = typeof(IDataRecordExtensions).GetMethod("GetEnum");
  46. private static readonly MethodInfo getConvertString = typeof(IDataRecordExtensions).GetMethod("GetConvertString");
  47. private static readonly MethodInfo getConvertFloat = typeof(IDataRecordExtensions).GetMethod("GetConvertFloat");
  48. private static readonly MethodInfo getConvertBoolean = typeof(IDataRecordExtensions).GetMethod("GetConvertBoolean");
  49. private static readonly MethodInfo getConvertByte = typeof(IDataRecordExtensions).GetMethod("GetConvertByte");
  50. private static readonly MethodInfo getConvertChar = typeof(IDataRecordExtensions).GetMethod("GetConvertChar");
  51. private static readonly MethodInfo getConvertDateTime = typeof(IDataRecordExtensions).GetMethod("GetConvertDateTime");
  52. private static readonly MethodInfo getConvertTime = typeof(IDataRecordExtensions).GetMethod("GetConvertTime");
  53. private static readonly MethodInfo getTime = typeof(IDataRecordExtensions).GetMethod("GetTime");
  54. private static readonly MethodInfo getConvertDecimal = typeof(IDataRecordExtensions).GetMethod("GetConvertDecimal");
  55. private static readonly MethodInfo getConvertDouble = typeof(IDataRecordExtensions).GetMethod("GetConvertDouble");
  56. private static readonly MethodInfo getConvertDoubleToFloat = typeof(IDataRecordExtensions).GetMethod("GetConvertDoubleToFloat");
  57. private static readonly MethodInfo getConvertGuid = typeof(IDataRecordExtensions).GetMethod("GetConvertGuid");
  58. private static readonly MethodInfo getConvertInt16 = typeof(IDataRecordExtensions).GetMethod("GetConvertInt16");
  59. private static readonly MethodInfo getConvertInt32 = typeof(IDataRecordExtensions).GetMethod("GetConvertInt32");
  60. private static readonly MethodInfo getConvertInt64 = typeof(IDataRecordExtensions).GetMethod("GetConvetInt64");
  61. private static readonly MethodInfo getConvertEnum_Null = typeof(IDataRecordExtensions).GetMethod("GetConvertEnum_Null");
  62. private static readonly MethodInfo getConvertdatetimeoffset = typeof(IDataRecordExtensions).GetMethod("GetConvertdatetimeoffset");
  63. private static readonly MethodInfo getConvertdatetimeoffsetDate = typeof(IDataRecordExtensions).GetMethod("GetConvertdatetimeoffsetDate");
  64. private static readonly MethodInfo getOtherNull = typeof(IDataRecordExtensions).GetMethod("GetOtherNull");
  65. private static readonly MethodInfo getOther = typeof(IDataRecordExtensions).GetMethod("GetOther");
  66. private static readonly MethodInfo getJson = typeof(IDataRecordExtensions).GetMethod("GetJson");
  67. private static readonly MethodInfo getArray = typeof(IDataRecordExtensions).GetMethod("GetArray");
  68. private static readonly MethodInfo getEntity = typeof(IDataRecordExtensions).GetMethod("GetEntity", new Type[] { typeof(SqlSugarProvider) });
  69. private delegate T Load(IDataRecord dataRecord);
  70. private Load handler;
  71. #endregion
  72. #region Constructor
  73. private IDataReaderEntityBuilder()
  74. {
  75. }
  76. public IDataReaderEntityBuilder(SqlSugarProvider context, IDataRecord dataRecord, List<string> fieldNames)
  77. {
  78. this.Context = context;
  79. this.DataRecord = dataRecord;
  80. this.DynamicBuilder = new IDataReaderEntityBuilder<T>();
  81. this.ReaderKeys = fieldNames;
  82. }
  83. #endregion
  84. #region Public methods
  85. public T Build(IDataRecord dataRecord)
  86. {
  87. return handler(dataRecord);
  88. }
  89. public IDataReaderEntityBuilder<T> CreateBuilder(Type type)
  90. {
  91. DynamicMethod method = new DynamicMethod("SqlSugarEntity", type,
  92. new Type[] { typeof(IDataRecord) }, type, true);
  93. ILGenerator generator = method.GetILGenerator();
  94. LocalBuilder result = generator.DeclareLocal(type);
  95. generator.Emit(OpCodes.Newobj, type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
  96. null, Type.EmptyTypes, null));
  97. generator.Emit(OpCodes.Stloc, result);
  98. this.Context.InitMappingInfo(type);
  99. var columnInfos = this.Context.EntityMaintenance.GetEntityInfoWithAttr(type).Columns;
  100. foreach (var columnInfo in columnInfos)
  101. {
  102. string fileName = columnInfo.DbColumnName ?? columnInfo.PropertyName;
  103. if (columnInfo.IsIgnore && !this.ReaderKeys.Any(it => it.Equals(fileName, StringComparison.CurrentCultureIgnoreCase)))
  104. {
  105. continue;
  106. }
  107. if (columnInfo != null && columnInfo.PropertyInfo.GetSetMethod(true) != null)
  108. {
  109. var isGemo = columnInfo.PropertyInfo?.PropertyType?.FullName=="NetTopologySuite.Geometries.Geometry";
  110. if (!isGemo&&columnInfo.PropertyInfo.PropertyType.IsClass() && columnInfo.PropertyInfo.PropertyType != UtilConstants.ByteArrayType && columnInfo.PropertyInfo.PropertyType != UtilConstants.ObjType)
  111. {
  112. if (this.ReaderKeys.Any(it => it.Equals(fileName, StringComparison.CurrentCultureIgnoreCase)))
  113. {
  114. BindClass(generator, result, columnInfo, ReaderKeys.First(it => it.Equals(fileName, StringComparison.CurrentCultureIgnoreCase)));
  115. }
  116. else if (this.ReaderKeys.Any(it => it.Equals(columnInfo.PropertyName, StringComparison.CurrentCultureIgnoreCase)))
  117. {
  118. BindClass(generator, result, columnInfo, ReaderKeys.First(it => it.Equals(columnInfo.PropertyName, StringComparison.CurrentCultureIgnoreCase)));
  119. }
  120. }
  121. else if (!isGemo && columnInfo.IsJson && columnInfo.PropertyInfo.PropertyType != UtilConstants.StringType)
  122. { //json is struct
  123. if (this.ReaderKeys.Any(it => it.Equals(fileName, StringComparison.CurrentCultureIgnoreCase)))
  124. {
  125. BindClass(generator, result, columnInfo, ReaderKeys.First(it => it.Equals(fileName, StringComparison.CurrentCultureIgnoreCase)));
  126. }
  127. }
  128. else
  129. {
  130. if (this.ReaderKeys.Any(it => it.Equals(fileName, StringComparison.CurrentCultureIgnoreCase)))
  131. {
  132. BindField(generator, result, columnInfo, ReaderKeys.First(it => it.Equals(fileName, StringComparison.CurrentCultureIgnoreCase)));
  133. }
  134. else if (this.ReaderKeys.Any(it => it.Equals(columnInfo.PropertyName, StringComparison.CurrentCultureIgnoreCase)))
  135. {
  136. BindField(generator, result, columnInfo, ReaderKeys.First(it => it.Equals(columnInfo.PropertyName, StringComparison.CurrentCultureIgnoreCase)));
  137. }
  138. }
  139. }
  140. }
  141. generator.Emit(OpCodes.Ldloc, result);
  142. generator.Emit(OpCodes.Ret);
  143. DynamicBuilder.handler = (Load)method.CreateDelegate(typeof(Load));
  144. return DynamicBuilder;
  145. }
  146. #endregion
  147. #region Private methods
  148. private void BindCustomFunc(ILGenerator generator, LocalBuilder result, EntityColumnInfo columnInfo, string fieldName)
  149. {
  150. int i = DataRecord.GetOrdinal(fieldName);
  151. Label endIfLabel = generator.DefineLabel();
  152. generator.Emit(OpCodes.Ldarg_0);
  153. generator.Emit(OpCodes.Ldc_I4, i);
  154. generator.Emit(OpCodes.Callvirt, isDBNullMethod);
  155. generator.Emit(OpCodes.Brtrue, endIfLabel);
  156. generator.Emit(OpCodes.Ldloc, result);
  157. //generator.Emit(OpCodes.Ldarg_0);
  158. //generator.Emit(OpCodes.Ldc_I4, i);
  159. var method = (columnInfo.SqlParameterDbType as Type).GetMethod("QueryConverter");
  160. method = method.MakeGenericMethod(new Type[] { columnInfo.PropertyInfo.PropertyType });
  161. Type type = (columnInfo.SqlParameterDbType as Type);
  162. //ConstructorInfo info = type.GetConstructor(Type.EmptyTypes);
  163. //il.Emit(OpCodes.Newobj, info);
  164. generator.Emit(OpCodes.Newobj, type.GetConstructor(Type.EmptyTypes));
  165. generator.Emit(OpCodes.Ldarg_0);
  166. generator.Emit(OpCodes.Ldc_I4, i);
  167. //method = (columnInfo.SqlParameterDbType as Type).GetMethod("QueryConverter");
  168. //method = method.MakeGenericMethod(new Type[] { columnInfo.PropertyInfo.PropertyType });
  169. if (method.IsVirtual)
  170. generator.Emit(OpCodes.Callvirt, method);
  171. else
  172. generator.Emit(OpCodes.Call, method);
  173. generator.Emit(OpCodes.Callvirt, columnInfo.PropertyInfo.GetSetMethod(true));
  174. generator.MarkLabel(endIfLabel);
  175. }
  176. private void BindClass(ILGenerator generator, LocalBuilder result, EntityColumnInfo columnInfo, string fieldName)
  177. {
  178. if (columnInfo.SqlParameterDbType is Type)
  179. {
  180. BindCustomFunc(generator, result, columnInfo, fieldName);
  181. return;
  182. }
  183. if (columnInfo.IsJson)
  184. {
  185. MethodInfo jsonMethod = getJson.MakeGenericMethod(columnInfo.PropertyInfo.PropertyType);
  186. int i = DataRecord.GetOrdinal(fieldName);
  187. Label endIfLabel = generator.DefineLabel();
  188. generator.Emit(OpCodes.Ldarg_0);
  189. generator.Emit(OpCodes.Ldc_I4, i);
  190. generator.Emit(OpCodes.Callvirt, isDBNullMethod);
  191. generator.Emit(OpCodes.Brtrue, endIfLabel);
  192. generator.Emit(OpCodes.Ldloc, result);
  193. generator.Emit(OpCodes.Ldarg_0);
  194. generator.Emit(OpCodes.Ldc_I4, i);
  195. generator.Emit(OpCodes.Call, jsonMethod);
  196. generator.Emit(OpCodes.Callvirt, columnInfo.PropertyInfo.GetSetMethod(true));
  197. generator.MarkLabel(endIfLabel);
  198. }
  199. if (columnInfo.IsArray)
  200. {
  201. MethodInfo arrayMehtod = getArray.MakeGenericMethod(columnInfo.PropertyInfo.PropertyType);
  202. int i = DataRecord.GetOrdinal(fieldName);
  203. Label endIfLabel = generator.DefineLabel();
  204. generator.Emit(OpCodes.Ldarg_0);
  205. generator.Emit(OpCodes.Ldc_I4, i);
  206. generator.Emit(OpCodes.Callvirt, isDBNullMethod);
  207. generator.Emit(OpCodes.Brtrue, endIfLabel);
  208. generator.Emit(OpCodes.Ldloc, result);
  209. generator.Emit(OpCodes.Ldarg_0);
  210. generator.Emit(OpCodes.Ldc_I4, i);
  211. generator.Emit(OpCodes.Call, arrayMehtod);
  212. generator.Emit(OpCodes.Callvirt, columnInfo.PropertyInfo.GetSetMethod(true));
  213. generator.MarkLabel(endIfLabel);
  214. }
  215. else if (columnInfo.UnderType == typeof(XElement))
  216. {
  217. int i = DataRecord.GetOrdinal(fieldName);
  218. Label endIfLabel = generator.DefineLabel();
  219. generator.Emit(OpCodes.Ldarg_0);
  220. generator.Emit(OpCodes.Ldc_I4, i);
  221. generator.Emit(OpCodes.Callvirt, isDBNullMethod);
  222. generator.Emit(OpCodes.Brtrue, endIfLabel);
  223. generator.Emit(OpCodes.Ldloc, result);
  224. generator.Emit(OpCodes.Ldarg_0);
  225. generator.Emit(OpCodes.Ldc_I4, i);
  226. BindMethod(generator, columnInfo, i);
  227. generator.Emit(OpCodes.Callvirt, columnInfo.PropertyInfo.GetSetMethod(true));
  228. generator.MarkLabel(endIfLabel);
  229. }
  230. }
  231. private void BindField(ILGenerator generator, LocalBuilder result, EntityColumnInfo columnInfo, string fieldName)
  232. {
  233. if (columnInfo.SqlParameterDbType is Type)
  234. {
  235. BindCustomFunc(generator,result, columnInfo, fieldName);
  236. return;
  237. }
  238. int i = DataRecord.GetOrdinal(fieldName);
  239. Label endIfLabel = generator.DefineLabel();
  240. //2023-3-8
  241. Label tryStart = generator.BeginExceptionBlock();//begin try
  242. //2023-3-8
  243. generator.Emit(OpCodes.Ldarg_0);
  244. generator.Emit(OpCodes.Ldc_I4, i);
  245. generator.Emit(OpCodes.Callvirt, isDBNullMethod);
  246. generator.Emit(OpCodes.Brtrue, endIfLabel);
  247. generator.Emit(OpCodes.Ldloc, result);
  248. generator.Emit(OpCodes.Ldarg_0);
  249. generator.Emit(OpCodes.Ldc_I4, i);
  250. BindMethod(generator, columnInfo, i);
  251. generator.Emit(OpCodes.Callvirt, columnInfo.PropertyInfo.GetSetMethod(true));
  252. generator.MarkLabel(endIfLabel);
  253. //2023-3-8
  254. generator.Emit(OpCodes.Leave, tryStart);//eng try
  255. generator.BeginCatchBlock(typeof(Exception));//begin catch
  256. generator.Emit(OpCodes.Ldstr, ErrorMessage.GetThrowMessage($"{columnInfo.EntityName} {columnInfo.PropertyName} bind error", $"{columnInfo.PropertyName}绑定到{columnInfo.EntityName}失败,可以试着换一个类型,或者使用ORM自定义类型实现"));//thow message
  257. generator.Emit(OpCodes.Newobj, typeof(Exception).GetConstructor(new Type[] { typeof(string) }));
  258. generator.Emit(OpCodes.Throw);
  259. generator.EndExceptionBlock();
  260. //2023-3-8
  261. }
  262. private void BindMethod(ILGenerator generator, EntityColumnInfo columnInfo, int ordinal)
  263. {
  264. IDbBind bind = Context.Ado.DbBind;
  265. bool isNullableType = false;
  266. MethodInfo method = null;
  267. Type bindPropertyType = UtilMethods.GetUnderType(columnInfo.PropertyInfo, ref isNullableType);
  268. string dbTypeName = UtilMethods.GetParenthesesValue(DataRecord.GetDataTypeName(ordinal));
  269. if (dbTypeName.IsNullOrEmpty())
  270. {
  271. dbTypeName = bindPropertyType.Name;
  272. }
  273. string propertyName = columnInfo.PropertyName;
  274. string validPropertyName = bind.GetPropertyTypeName(dbTypeName);
  275. validPropertyName = validPropertyName == "byte[]" ? "byteArray" : validPropertyName;
  276. CSharpDataType validPropertyType = (CSharpDataType)Enum.Parse(typeof(CSharpDataType), validPropertyName);
  277. #region Sqlite Logic
  278. if (this.Context.CurrentConnectionConfig.DbType == DbType.Sqlite)
  279. {
  280. if (bindPropertyType.IsEnum())
  281. {
  282. method = isNullableType ? getConvertEnum_Null.MakeGenericMethod(bindPropertyType) : getEnum.MakeGenericMethod(bindPropertyType);
  283. }
  284. else if (bindPropertyType == UtilConstants.IntType)
  285. {
  286. method = isNullableType ? getConvertInt32 : getInt32;
  287. }
  288. else if (bindPropertyType == UtilConstants.DateTimeOffsetType&&SugarCompatible.IsFramework)
  289. {
  290. method = isNullableType ? getConvertdatetimeoffset : getdatetimeoffset;
  291. }
  292. else if (bindPropertyType == UtilConstants.ByteType)
  293. {
  294. method = isNullableType ? getConvertByte : getByte;
  295. }
  296. else if (bindPropertyType == UtilConstants.StringType && dbTypeName?.ToLower() == "timestamp")
  297. {
  298. method = isNullableType ? getOtherNull.MakeGenericMethod(bindPropertyType) : getOther.MakeGenericMethod(bindPropertyType);
  299. }
  300. else if (dbTypeName.EqualCase("STRING"))
  301. {
  302. method = isNullableType ? getOtherNull.MakeGenericMethod(bindPropertyType) : getOther.MakeGenericMethod(bindPropertyType);
  303. }
  304. else if (bindPropertyType == UtilConstants.StringType&&validPropertyName == "int")
  305. {
  306. method = isNullableType ? getOtherNull.MakeGenericMethod(bindPropertyType) : getOther.MakeGenericMethod(bindPropertyType);
  307. }
  308. else if (bindPropertyType == UtilConstants.StringType)
  309. {
  310. method = getString;
  311. }
  312. else
  313. {
  314. method = isNullableType ? getOtherNull.MakeGenericMethod(bindPropertyType) : getOther.MakeGenericMethod(bindPropertyType);
  315. }
  316. if (method.IsVirtual)
  317. generator.Emit(OpCodes.Callvirt, method);
  318. else
  319. generator.Emit(OpCodes.Call, method);
  320. return;
  321. };
  322. #endregion
  323. #region Common Database Logic
  324. string bindProperyTypeName = bindPropertyType.Name.ToLower();
  325. bool isEnum = bindPropertyType.IsEnum();
  326. if (isEnum) { validPropertyType = CSharpDataType.@enum; }
  327. switch (validPropertyType)
  328. {
  329. case CSharpDataType.@int:
  330. CheckType(bind.IntThrow, bindProperyTypeName, validPropertyName, propertyName);
  331. if (bindProperyTypeName.IsContainsIn("int", "int32"))
  332. method = isNullableType ? getConvertInt32 : getInt32;
  333. if (bindProperyTypeName.IsContainsIn("int64"))
  334. method = null;
  335. if (bindProperyTypeName.IsContainsIn("byte"))
  336. method = isNullableType ? getConvertByte : getByte;
  337. if (bindProperyTypeName.IsContainsIn("int16"))
  338. method = isNullableType ? getConvertInt16 : getInt16;
  339. if (bindProperyTypeName == "uint32"&&this.Context.CurrentConnectionConfig.DbType.IsIn(DbType.MySql,DbType.MySqlConnector))
  340. method = null;
  341. break;
  342. case CSharpDataType.@bool:
  343. if (bindProperyTypeName == "bool" || bindProperyTypeName == "boolean")
  344. method = isNullableType ? getConvertBoolean : getBoolean;
  345. break;
  346. case CSharpDataType.@string:
  347. if (this.Context.CurrentConnectionConfig.DbType != DbType.Oracle)
  348. {
  349. CheckType(bind.StringThrow, bindProperyTypeName, validPropertyName, propertyName);
  350. }
  351. method = getString;
  352. if (bindProperyTypeName == "guid")
  353. {
  354. method = isNullableType ? getConvertStringGuid : getStringGuid;
  355. }
  356. else if (bindProperyTypeName == "xelement")
  357. {
  358. method = getXelement;
  359. }
  360. else if (dbTypeName == "CHAR" && DataRecord.GetDataTypeName(ordinal) == "CHAR(36)")
  361. {
  362. method = null;
  363. }
  364. else if (bindPropertyType.Name == "Char")
  365. {
  366. method = null;
  367. }
  368. break;
  369. case CSharpDataType.DateTime:
  370. CheckType(bind.DateThrow, bindProperyTypeName, validPropertyName, propertyName);
  371. if (bindProperyTypeName == "datetime")
  372. method = isNullableType ? getConvertDateTime : getDateTime;
  373. if (bindProperyTypeName == "datetime" && dbTypeName.ToLower() == "time")
  374. method = isNullableType ? getConvertTime : getTime;
  375. if (bindProperyTypeName == "datetimeoffset")
  376. method = isNullableType ? getConvertdatetimeoffset : getdatetimeoffset;
  377. break;
  378. case CSharpDataType.@decimal:
  379. CheckType(bind.DecimalThrow, bindProperyTypeName, validPropertyName, propertyName);
  380. if (bindProperyTypeName == "decimal")
  381. method = isNullableType ? getConvertDecimal : getDecimal;
  382. break;
  383. case CSharpDataType.@float:
  384. case CSharpDataType.@double:
  385. CheckType(bind.DoubleThrow, bindProperyTypeName, validPropertyName, propertyName);
  386. if (bindProperyTypeName.IsIn("double", "single") && dbTypeName != "real")
  387. method = isNullableType ? getConvertDouble : getDouble;
  388. else
  389. method = isNullableType ? getConvertFloat : getFloat;
  390. if (dbTypeName.Equals("float", StringComparison.CurrentCultureIgnoreCase) && isNullableType && bindProperyTypeName.Equals("single", StringComparison.CurrentCultureIgnoreCase))
  391. {
  392. method = getConvertDoubleToFloat;
  393. }
  394. if (bindPropertyType == UtilConstants.DecType)
  395. {
  396. method = isNullableType ? getOtherNull.MakeGenericMethod(bindPropertyType) : getOther.MakeGenericMethod(bindPropertyType);
  397. }
  398. if (bindPropertyType == UtilConstants.IntType)
  399. {
  400. method = isNullableType ? getOtherNull.MakeGenericMethod(bindPropertyType) : getOther.MakeGenericMethod(bindPropertyType);
  401. }
  402. if (bindProperyTypeName == "string")
  403. {
  404. method = null;
  405. }
  406. break;
  407. case CSharpDataType.Guid:
  408. CheckType(bind.GuidThrow, bindProperyTypeName, validPropertyName, propertyName);
  409. if (bindProperyTypeName == "guid")
  410. method = isNullableType ? getConvertGuid : getGuid;
  411. break;
  412. case CSharpDataType.@byte:
  413. if (bindProperyTypeName == "byte")
  414. method = isNullableType ? getConvertByte : getByte;
  415. break;
  416. case CSharpDataType.@enum:
  417. method = isNullableType ? getConvertEnum_Null.MakeGenericMethod(bindPropertyType) : getEnum.MakeGenericMethod(bindPropertyType);
  418. break;
  419. case CSharpDataType.@short:
  420. CheckType(bind.ShortThrow, bindProperyTypeName, validPropertyName, propertyName);
  421. if (bindProperyTypeName == "int16" || bindProperyTypeName == "short")
  422. method = isNullableType ? getConvertInt16 : getInt16;
  423. break;
  424. case CSharpDataType.@long:
  425. if (bindProperyTypeName == "int64" || bindProperyTypeName == "long")
  426. method = isNullableType ? getConvertInt64 : getInt64;
  427. break;
  428. case CSharpDataType.DateTimeOffset:
  429. method = isNullableType ? getConvertdatetimeoffset : getdatetimeoffset;
  430. if (bindProperyTypeName == "datetime")
  431. method = isNullableType ? getConvertdatetimeoffsetDate : getdatetimeoffsetDate;
  432. break;
  433. case CSharpDataType.Single:
  434. break;
  435. default:
  436. method = isNullableType ? getOtherNull.MakeGenericMethod(bindPropertyType) : getOther.MakeGenericMethod(bindPropertyType);
  437. break;
  438. }
  439. if (method == null && bindPropertyType == UtilConstants.StringType)
  440. {
  441. method = getConvertString;
  442. }
  443. if (bindPropertyType == UtilConstants.ObjType)
  444. {
  445. method = isNullableType ? getOtherNull.MakeGenericMethod(bindPropertyType) : getOther.MakeGenericMethod(bindPropertyType);
  446. }
  447. if (method == null)
  448. method = isNullableType ? getOtherNull.MakeGenericMethod(bindPropertyType) : getOther.MakeGenericMethod(bindPropertyType);
  449. if (method.IsVirtual)
  450. generator.Emit(OpCodes.Callvirt, method);
  451. else
  452. generator.Emit(OpCodes.Call, method);
  453. #endregion
  454. }
  455. private void CheckType(List<string> invalidTypes, string bindProperyTypeName, string validPropertyType, string propertyName)
  456. {
  457. var isAny = invalidTypes.Contains(bindProperyTypeName);
  458. if (isAny)
  459. {
  460. throw new SqlSugarException(string.Format("{0} can't convert {1} to {2}", propertyName, validPropertyType, bindProperyTypeName));
  461. }
  462. }
  463. #endregion
  464. }
  465. }