OracleDynamicParameters.cs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data;
  4. using System.Linq;
  5. using Dapper;
  6. using Oracle.ManagedDataAccess.Client;
  7. namespace Host.Repositories
  8. {
  9. internal class OracleDynamicParameters
  10. {
  11. private static Dictionary<SqlMapper.Identity, Action<IDbCommand, object>> paramReaderCache = new Dictionary<SqlMapper.Identity, Action<IDbCommand, object>>();
  12. private Dictionary<string, ParamInfo> parameters = new Dictionary<string, ParamInfo>();
  13. private List<object> templates;
  14. private class ParamInfo
  15. {
  16. public string Name { get; set; }
  17. public object Value { get; set; }
  18. public ParameterDirection ParameterDirection { get; set; }
  19. public OracleDbType? DbType { get; set; }
  20. public int? Size { get; set; }
  21. public IDbDataParameter AttachedParam { get; set; }
  22. }
  23. /// <summary>
  24. /// construct a dynamic parameter bag
  25. /// </summary>
  26. public OracleDynamicParameters()
  27. {
  28. }
  29. /// <summary>
  30. /// construct a dynamic parameter bag
  31. /// </summary>
  32. /// <param name="template">can be an anonymous type or a DynamicParameters bag</param>
  33. public OracleDynamicParameters(object template)
  34. {
  35. AddDynamicParams(template);
  36. }
  37. /// <summary>
  38. /// Append a whole object full of params to the dynamic
  39. /// EG: AddDynamicParams(new {A = 1, B = 2}) // will add property A and B to the dynamic
  40. /// </summary>
  41. /// <param name="param"></param>
  42. public void AddDynamicParams(
  43. #if CSHARP30
  44. object param
  45. #else
  46. dynamic param
  47. #endif
  48. )
  49. {
  50. var obj = param as object;
  51. if (obj != null)
  52. {
  53. var subDynamic = obj as OracleDynamicParameters;
  54. if (subDynamic == null)
  55. {
  56. var dictionary = obj as IEnumerable<KeyValuePair<string, object>>;
  57. if (dictionary == null)
  58. {
  59. templates = templates ?? new List<object>();
  60. templates.Add(obj);
  61. }
  62. else
  63. {
  64. foreach (var kvp in dictionary)
  65. {
  66. #if CSHARP30
  67. Add(kvp.Key, kvp.Value, null, null, null);
  68. #else
  69. Add(kvp.Key, kvp.Value);
  70. #endif
  71. }
  72. }
  73. }
  74. else
  75. {
  76. if (subDynamic.parameters != null)
  77. {
  78. foreach (var kvp in subDynamic.parameters)
  79. {
  80. parameters.Add(kvp.Key, kvp.Value);
  81. }
  82. }
  83. if (subDynamic.templates != null)
  84. {
  85. templates = templates ?? new List<object>();
  86. foreach (var t in subDynamic.templates)
  87. {
  88. templates.Add(t);
  89. }
  90. }
  91. }
  92. }
  93. }
  94. /// <summary>
  95. /// Add a parameter to this dynamic parameter list
  96. /// </summary>
  97. /// <param name="name"></param>
  98. /// <param name="value"></param>
  99. /// <param name="dbType"></param>
  100. /// <param name="direction"></param>
  101. /// <param name="size"></param>
  102. public void Add(
  103. #if CSHARP30
  104. string name, object value, DbType? dbType, ParameterDirection? direction, int? size
  105. #else
  106. string name, object value = null, OracleDbType? dbType = null, ParameterDirection? direction = null, int? size = null
  107. #endif
  108. )
  109. {
  110. parameters[Clean(name)] = new ParamInfo() { Name = name, Value = value, ParameterDirection = direction ?? ParameterDirection.Input, DbType = dbType, Size = size };
  111. }
  112. private static string Clean(string name)
  113. {
  114. if (!string.IsNullOrEmpty(name))
  115. {
  116. switch (name[0])
  117. {
  118. case '@':
  119. case ':':
  120. case '?':
  121. return name.Substring(1);
  122. }
  123. }
  124. return name;
  125. }
  126. /// <summary>
  127. /// Add all the parameters needed to the command just before it executes
  128. /// </summary>
  129. /// <param name="command">The raw command prior to execution</param>
  130. /// <param name="identity">Information about the query</param>
  131. protected void AddParameters(IDbCommand command, SqlMapper.Identity identity)
  132. {
  133. if (templates != null)
  134. {
  135. foreach (var template in templates)
  136. {
  137. var newIdent = identity.ForDynamicParameters(template.GetType());
  138. Action<IDbCommand, object> appender;
  139. lock (paramReaderCache)
  140. {
  141. if (!paramReaderCache.TryGetValue(newIdent, out appender))
  142. {
  143. appender = SqlMapper.CreateParamInfoGenerator(newIdent, false, false);
  144. paramReaderCache[newIdent] = appender;
  145. }
  146. }
  147. appender(command, template);
  148. }
  149. }
  150. foreach (var param in parameters.Values)
  151. {
  152. string name = Clean(param.Name);
  153. bool add = !((OracleCommand)command).Parameters.Contains(name);
  154. OracleParameter p;
  155. if (add)
  156. {
  157. p = ((OracleCommand)command).CreateParameter();
  158. p.ParameterName = name;
  159. }
  160. else
  161. {
  162. p = ((OracleCommand)command).Parameters[name];
  163. }
  164. var val = param.Value;
  165. p.Value = val ?? DBNull.Value;
  166. p.Direction = param.ParameterDirection;
  167. var s = val as string;
  168. if (s != null)
  169. {
  170. if (s.Length <= 4000)
  171. {
  172. p.Size = 4000;
  173. }
  174. }
  175. if (param.Size != null)
  176. {
  177. p.Size = param.Size.Value;
  178. }
  179. if (param.DbType != null)
  180. {
  181. p.OracleDbType = param.DbType.Value;
  182. }
  183. if (add)
  184. {
  185. command.Parameters.Add(p);
  186. }
  187. param.AttachedParam = p;
  188. }
  189. }
  190. /// <summary>
  191. /// All the names of the param in the bag, use Get to yank them out
  192. /// </summary>
  193. public IEnumerable<string> ParameterNames
  194. {
  195. get
  196. {
  197. return parameters.Select(p => p.Key);
  198. }
  199. }
  200. /// <summary>
  201. /// Get the value of a parameter
  202. /// </summary>
  203. /// <typeparam name="T"></typeparam>
  204. /// <param name="name"></param>
  205. /// <returns>The value, note DBNull.Value is not returned, instead the value is returned as null</returns>
  206. public T Get<T>(string name)
  207. {
  208. var val = parameters[Clean(name)].AttachedParam.Value;
  209. if (val == DBNull.Value)
  210. {
  211. if (default(T) != null)
  212. {
  213. throw new ApplicationException("Attempting to cast a DBNull to a non nullable type!");
  214. }
  215. return default(T);
  216. }
  217. return (T)val;
  218. }
  219. }
  220. }