/1.0.x.x/Anito.Data.SqlClient/Mapper.cs

# · C# · 349 lines · 286 code · 57 blank · 6 comment · 37 complexity · b41c5afdbb1b895d0172ff8ac334c798 MD5 · raw file

  1. /////////////////////////////////////////////////////////////////////////////////////////////////////
  2. // Original Code by : Michael Dela Cuesta (michael.dcuesta@gmail.com) //
  3. // Source Code Available : http://anito.codeplex.com //
  4. // //
  5. // This source code is made available under the terms of the Microsoft Public License (MS-PL) //
  6. /////////////////////////////////////////////////////////////////////////////////////////////////////
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Linq;
  10. using System.Text;
  11. using System.Data;
  12. using System.Data.Common;
  13. using Anito.Data;
  14. using System.Reflection.Emit;
  15. using System.Reflection;
  16. using Anito.Data.Util;
  17. namespace Anito.Data.SqlClient
  18. {
  19. public class Mapper: Anito.Data.IMapper
  20. {
  21. #region Variables
  22. private static Dictionary<Type, Delegate> m_mapperCache;
  23. #endregion
  24. #region Properties
  25. #region Provider
  26. public IProvider Provider
  27. {
  28. get;
  29. set;
  30. }
  31. #endregion
  32. #region MapperCache
  33. private Dictionary<Type, Delegate> MapperCache
  34. {
  35. get
  36. {
  37. if (m_mapperCache == null)
  38. m_mapperCache = new Dictionary<Type, Delegate>();
  39. return m_mapperCache;
  40. }
  41. }
  42. #endregion
  43. #endregion
  44. #region Constructor
  45. public Mapper(IProvider provider)
  46. {
  47. Provider = provider;
  48. }
  49. #endregion
  50. #region GetMappingMethods
  51. ToDataObjectDelegate<T> IMapper.GetDataObjectMappingMethod<T>()
  52. {
  53. return GetIDataObjectMapper<T>();
  54. }
  55. ToDataObjectDelegate IMapper.GetDataObjectMappingMethod(Type type)
  56. {
  57. return GetIDataObjectMapper(type);
  58. }
  59. ToTDelegate<T> IMapper.GetTMappingMethod<T>()
  60. {
  61. return GetObjectMapper<T>();
  62. }
  63. ToObjectDelegate IMapper.GetObjectMappingMethod(Type type)
  64. {
  65. return GetObjectMapper(type);
  66. }
  67. #endregion
  68. #region Mapping
  69. #region GetMappers
  70. private ToTDelegate<T> GetObjectMapper<T>()
  71. {
  72. if (!MapperCache.ContainsKey(typeof(T)))
  73. {
  74. Type[] methodArgs = { typeof(DbDataReader) };
  75. DynamicMethod dm = new DynamicMethod("MapDatareader", typeof(T), methodArgs, typeof(T));
  76. ILGenerator il = dm.GetILGenerator();
  77. il.DeclareLocal(typeof(T));
  78. il.Emit(OpCodes.Newobj, typeof(T).GetConstructor(Type.EmptyTypes));
  79. il.Emit(OpCodes.Stloc_0);
  80. CreateAssignmentMethods<T>(il);
  81. il.Emit(OpCodes.Ldloc_0);
  82. il.Emit(OpCodes.Ret);
  83. MapperCache.Add(typeof(T), dm.CreateDelegate(typeof(ToTDelegate<T>)));
  84. }
  85. return (ToTDelegate<T>)MapperCache[typeof(T)];
  86. }
  87. private ToObjectDelegate GetObjectMapper(Type type)
  88. {
  89. if (!MapperCache.ContainsKey(type))
  90. {
  91. Type[] methodArgs = { typeof(DbDataReader) };
  92. DynamicMethod dm = new DynamicMethod("MapDatareader", type, methodArgs, type);
  93. ILGenerator il = dm.GetILGenerator();
  94. il.DeclareLocal(type);
  95. il.Emit(OpCodes.Newobj, type.GetConstructor(Type.EmptyTypes));
  96. il.Emit(OpCodes.Stloc_0);
  97. CreateAssignmentMethods(type, il);
  98. il.Emit(OpCodes.Ldloc_0);
  99. il.Emit(OpCodes.Ret);
  100. MapperCache.Add(type, dm.CreateDelegate(typeof(ToObjectDelegate)));
  101. }
  102. return (ToObjectDelegate)MapperCache[type];
  103. }
  104. private ToDataObjectDelegate<T> GetIDataObjectMapper<T>()
  105. {
  106. if (!MapperCache.ContainsKey(typeof(T)))
  107. {
  108. Type[] methodArgs = { typeof(DbDataReader), typeof(ISession) };
  109. DynamicMethod dm = new DynamicMethod("MapDatareader", typeof(T), methodArgs, typeof(T));
  110. ILGenerator il = dm.GetILGenerator();
  111. il.DeclareLocal(typeof(T));
  112. il.Emit(OpCodes.Ldarg_1);
  113. il.Emit(OpCodes.Newobj, typeof(T).GetConstructor(new Type[] { typeof(ISession) }));
  114. il.Emit(OpCodes.Stloc_0);
  115. CreateAssignmentMethods<T>(il);
  116. il.Emit(OpCodes.Ldloc_0);
  117. il.Emit(OpCodes.Call, typeof(IDataObject).GetMethod("AcceptChanges"));
  118. il.Emit(OpCodes.Ldloc_0);
  119. il.Emit(OpCodes.Ret);
  120. MapperCache.Add(typeof(T), dm.CreateDelegate(typeof(ToDataObjectDelegate<T>)));
  121. }
  122. return (ToDataObjectDelegate<T>)MapperCache[typeof(T)];
  123. }
  124. private ToDataObjectDelegate GetIDataObjectMapper(Type type)
  125. {
  126. if (!MapperCache.ContainsKey(type))
  127. {
  128. Type[] methodArgs = { typeof(DbDataReader), typeof(ISession) };
  129. DynamicMethod dm = new DynamicMethod("MapDatareader", type, methodArgs, type);
  130. ILGenerator il = dm.GetILGenerator();
  131. il.DeclareLocal(type);
  132. il.Emit(OpCodes.Ldarg_1);
  133. il.Emit(OpCodes.Newobj, type.GetConstructor(new Type[] { typeof(ISession) }));
  134. il.Emit(OpCodes.Stloc_0);
  135. CreateAssignmentMethods(type, il);
  136. il.Emit(OpCodes.Ldloc_0);
  137. il.Emit(OpCodes.Call, typeof(IDataObject).GetMethod("AcceptChanges"));
  138. il.Emit(OpCodes.Ldloc_0);
  139. il.Emit(OpCodes.Ret);
  140. MapperCache.Add(type, dm.CreateDelegate(typeof(ToDataObjectDelegate)));
  141. }
  142. return (ToDataObjectDelegate)MapperCache[type];
  143. }
  144. #endregion
  145. #region CreateAssignmentMethod
  146. private void CreateAssignmentMethods<T>(ILGenerator il)
  147. {
  148. Type typeT = typeof(T);
  149. Anito.Data.Schema.TypeTable schemaTable = Provider.GetSchema(typeT);
  150. foreach (Anito.Data.Schema.TypeColumn column in schemaTable)
  151. {
  152. il.Emit(OpCodes.Ldloc_0);
  153. il.Emit(OpCodes.Ldarg_0);
  154. il.Emit(OpCodes.Ldstr, column.Name);
  155. MethodInfo methodInfo = typeof(DbDataReader).GetMethod("get_Item", new Type[] { typeof(string) });
  156. il.Emit(OpCodes.Callvirt, methodInfo);
  157. if (column.IsNullable || column.Type == typeof(string))
  158. InitMethodParam(il, column.Type, column.IsNullable);
  159. else if(Misc.IsNumericType(column.Type) || typeof(Guid) == column.Type || typeof(DateTime) == column.Type)
  160. InitMethodParam(il, column.Type);
  161. if (column.StructureStructureType == Anito.Data.Schema.TypeColumn.ColumnStructureType.Field)
  162. il.Emit(OpCodes.Stfld, typeof(T).GetField(column.MemberName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance));
  163. else if (column.StructureStructureType == Anito.Data.Schema.TypeColumn.ColumnStructureType.Property)
  164. il.Emit(OpCodes.Callvirt, typeof(T).GetMethod("set_" + column.MemberName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance));
  165. else
  166. il.Emit(OpCodes.Stfld, typeof(T).GetField(column.MemberName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance));
  167. }
  168. }
  169. private void CreateAssignmentMethods(Type typeT, ILGenerator il)
  170. {
  171. Anito.Data.Schema.TypeTable schemaTable = Provider.GetSchema(typeT);
  172. foreach (Anito.Data.Schema.TypeColumn column in schemaTable)
  173. {
  174. il.Emit(OpCodes.Ldloc_0);
  175. il.Emit(OpCodes.Ldarg_0);
  176. il.Emit(OpCodes.Ldstr, column.Name);
  177. MethodInfo methodInfo = typeof(DbDataReader).GetMethod("get_Item", new Type[] { typeof(string) });
  178. il.Emit(OpCodes.Callvirt, methodInfo);
  179. if (column.IsNullable || column.Type == typeof(string))
  180. InitMethodParam(il, column.Type, column.IsNullable);
  181. else if (Misc.IsNumericType(column.Type) || typeof(Guid) == column.Type || typeof(DateTime) == column.Type)
  182. InitMethodParam(il, column.Type);
  183. if (column.StructureStructureType == Anito.Data.Schema.TypeColumn.ColumnStructureType.Field)
  184. il.Emit(OpCodes.Stfld, typeT.GetField(column.MemberName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance));
  185. else if (column.StructureStructureType == Anito.Data.Schema.TypeColumn.ColumnStructureType.Property)
  186. il.Emit(OpCodes.Callvirt, typeT.GetMethod("set_" + column.MemberName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance));
  187. else
  188. il.Emit(OpCodes.Stfld, typeT.GetField(column.MemberName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance));
  189. }
  190. }
  191. #endregion
  192. #region InitMethodParam
  193. protected virtual void InitMethodParam(ILGenerator il, Type type)
  194. {
  195. switch (type.Name.ToUpper())
  196. {
  197. case "INT16":
  198. il.Emit(OpCodes.Call, CreateConverterMethodInfo("ToInt16"));
  199. break;
  200. case "INT32":
  201. il.Emit(OpCodes.Call, CreateConverterMethodInfo("ToInt32"));
  202. break;
  203. case "INT64":
  204. il.Emit(OpCodes.Call, CreateConverterMethodInfo("ToInt64"));
  205. break;
  206. case "SINGLE":
  207. il.Emit(OpCodes.Call, CreateConverterMethodInfo("ToSingle"));
  208. break;
  209. case "BOOLEAN":
  210. il.Emit(OpCodes.Call, CreateConverterMethodInfo("ToBoolean"));
  211. break;
  212. case "STRING":
  213. il.Emit(OpCodes.Call, CreateConverterMethodInfo("ToString"));
  214. break;
  215. case "DATETIME":
  216. il.Emit(OpCodes.Call, CreateConverterMethodInfo("ToDateTime"));
  217. break;
  218. case "DECIMAL":
  219. il.Emit(OpCodes.Call, CreateConverterMethodInfo("ToDecimal"));
  220. break;
  221. case "DOUBLE":
  222. il.Emit(OpCodes.Call, CreateConverterMethodInfo("ToDouble"));
  223. break;
  224. case "GUID":
  225. il.Emit(OpCodes.Call, CreateConverterMethodInfo("ToGuid"));
  226. break;
  227. case "BYTE[]":
  228. il.Emit(OpCodes.Call, CreateConverterMethodInfo("ToBytes"));
  229. break;
  230. case "BYTE":
  231. il.Emit(OpCodes.Call, CreateConverterMethodInfo("ToByte"));
  232. break;
  233. }
  234. }
  235. protected virtual void InitMethodParam(ILGenerator il, Type type, bool isNullable)
  236. {
  237. switch (type.Name.ToUpper())
  238. {
  239. case "INT16":
  240. il.Emit(OpCodes.Call, CreateConverterMethodInfo("ToInt16", isNullable));
  241. break;
  242. case "INT32":
  243. il.Emit(OpCodes.Call, CreateConverterMethodInfo("ToInt32", isNullable));
  244. break;
  245. case "INT64":
  246. il.Emit(OpCodes.Call, CreateConverterMethodInfo("ToInt64", isNullable));
  247. break;
  248. case "SINGLE":
  249. il.Emit(OpCodes.Call, CreateConverterMethodInfo("ToSingle", isNullable));
  250. break;
  251. case "BOOLEAN":
  252. il.Emit(OpCodes.Call, CreateConverterMethodInfo("ToBoolean", isNullable));
  253. break;
  254. case "STRING":
  255. il.Emit(OpCodes.Call, CreateConverterMethodInfo("ToString", isNullable));
  256. break;
  257. case "DATETIME":
  258. il.Emit(OpCodes.Call, CreateConverterMethodInfo("ToDateTime", isNullable));
  259. break;
  260. case "DECIMAL":
  261. il.Emit(OpCodes.Call, CreateConverterMethodInfo("ToDecimal", isNullable));
  262. break;
  263. case "DOUBLE":
  264. il.Emit(OpCodes.Call, CreateConverterMethodInfo("ToDouble", isNullable));
  265. break;
  266. case "GUID":
  267. il.Emit(OpCodes.Call, CreateConverterMethodInfo("ToGuid", isNullable));
  268. break;
  269. case "BYTE[]":
  270. il.Emit(OpCodes.Call, CreateConverterMethodInfo("ToBytes", isNullable));
  271. break;
  272. case "BYTE":
  273. il.Emit(OpCodes.Call, CreateConverterMethodInfo("ToByte", isNullable));
  274. break;
  275. }
  276. }
  277. #endregion
  278. #region CreateConverterMethodInfo
  279. protected virtual MethodInfo CreateConverterMethodInfo(string method)
  280. {
  281. return typeof(Converter).GetMethod(method, new Type[] { typeof(object) });
  282. }
  283. protected virtual MethodInfo CreateConverterMethodInfo(string method, bool isNullable)
  284. {
  285. if(isNullable)
  286. return typeof(DbNullConverter).GetMethod(method, new Type[] { typeof(object) });
  287. return typeof(Converter).GetMethod(method, new Type[] { typeof(object) });
  288. }
  289. #endregion
  290. #endregion
  291. }
  292. }