/Rhino.Etl.Core/Infrastructure/Use.cs

http://github.com/ayende/rhino-etl · C# · 260 lines · 141 code · 28 blank · 91 comment · 24 complexity · 05b81833d39aac6a845fbbb6db5f7d10 MD5 · raw file

  1. using System;
  2. using System.Configuration;
  3. using System.Data;
  4. namespace Rhino.Etl.Core.Infrastructure
  5. {
  6. using System.Data.Common;
  7. /// <summary>
  8. /// Helper class to provide simple data access, when we want to access the ADO.Net
  9. /// library directly.
  10. /// </summary>
  11. public static class Use
  12. {
  13. #region Delegates
  14. /// <summary>
  15. /// Delegate to execute an action with a command
  16. /// and return a result: <typeparam name="T"/>
  17. /// </summary>
  18. public delegate T Func<T>(IDbCommand command);
  19. /// <summary>
  20. /// Delegate to execute an action with a command
  21. /// </summary>
  22. public delegate void Proc(IDbCommand command);
  23. #endregion
  24. /// <summary>
  25. /// Gets or sets the active connection.
  26. /// </summary>
  27. /// <value>The active connection.</value>
  28. [ThreadStatic]
  29. private static IDbConnection ActiveConnection;
  30. /// <summary>
  31. /// Gets or sets the active transaction.
  32. /// </summary>
  33. /// <value>The active transaction.</value>
  34. [ThreadStatic]
  35. private static IDbTransaction ActiveTransaction;
  36. /// <summary>
  37. /// Gets or sets the transaction counter.
  38. /// </summary>
  39. /// <value>The transaction counter.</value>
  40. [ThreadStatic]
  41. private static int TransactionCounter;
  42. /// <summary>
  43. /// Execute the specified delegate inside a transaction and return
  44. /// the result of the delegate.
  45. /// </summary>
  46. /// <typeparam name="T"></typeparam>
  47. /// <param name="connectionStringName">The name of the named connection string in the configuration file</param>
  48. /// <param name="actionToExecute">The action to execute</param>
  49. /// <returns></returns>
  50. public static T Transaction<T>(string connectionStringName, Func<T> actionToExecute)
  51. {
  52. T result = default(T);
  53. ConnectionStringSettings connectionStringSettings = ConfigurationManager.ConnectionStrings[connectionStringName];
  54. if (connectionStringSettings == null)
  55. throw new InvalidOperationException("Could not find connnection string: " + connectionStringName);
  56. Transaction(connectionStringSettings, delegate(IDbCommand command) { result = actionToExecute(command); });
  57. return result;
  58. }
  59. /// <summary>
  60. /// Execute the specified delegate inside a transaction and return
  61. /// the result of the delegate.
  62. /// </summary>
  63. /// <typeparam name="T"></typeparam>
  64. /// <param name="connectionStringSettings">The connection string settings to use for the connection</param>
  65. /// <param name="actionToExecute">The action to execute</param>
  66. /// <returns></returns>
  67. public static T Transaction<T>(ConnectionStringSettings connectionStringSettings, Func<T> actionToExecute)
  68. {
  69. T result = default(T);
  70. Transaction(connectionStringSettings, delegate(IDbCommand command) { result = actionToExecute(command); });
  71. return result;
  72. }
  73. /// <summary>
  74. /// Execute the specified delegate inside a transaction
  75. /// </summary>
  76. /// <param name="connectionStringName">Name of the connection string.</param>
  77. /// <param name="actionToExecute">The action to execute.</param>
  78. public static void Transaction(string connectionStringName, Proc actionToExecute)
  79. {
  80. ConnectionStringSettings connectionStringSettings = ConfigurationManager.ConnectionStrings[connectionStringName];
  81. if (connectionStringSettings == null)
  82. throw new InvalidOperationException("Could not find connnection string: " + connectionStringName);
  83. Transaction(connectionStringSettings, IsolationLevel.Unspecified, actionToExecute);
  84. }
  85. /// <summary>
  86. /// Execute the specified delegate inside a transaction
  87. /// </summary>
  88. /// <param name="connectionStringSettings">The connection string settings to use for the connection</param>
  89. /// <param name="actionToExecute">The action to execute.</param>
  90. public static void Transaction(ConnectionStringSettings connectionStringSettings, Proc actionToExecute)
  91. {
  92. Transaction(connectionStringSettings, IsolationLevel.Unspecified, actionToExecute);
  93. }
  94. /// <summary>
  95. /// Execute the specified delegate inside a transaction with the specific
  96. /// isolation level
  97. /// </summary>
  98. /// <param name="connectionStringName">Name of the connection string.</param>
  99. /// <param name="isolationLevel">The isolation level.</param>
  100. /// <param name="actionToExecute">The action to execute.</param>
  101. public static void Transaction(string connectionStringName, IsolationLevel isolationLevel, Proc actionToExecute)
  102. {
  103. ConnectionStringSettings connectionStringSettings = ConfigurationManager.ConnectionStrings[connectionStringName];
  104. if (connectionStringSettings == null)
  105. throw new InvalidOperationException("Could not find connnection string: " + connectionStringName);
  106. Transaction(connectionStringSettings, isolationLevel, actionToExecute);
  107. }
  108. /// <summary>
  109. /// Execute the specified delegate inside a transaction with the specific
  110. /// isolation level
  111. /// </summary>
  112. /// <param name="connectionStringSettings">Connection string settings node to use for the connection</param>
  113. /// <param name="isolationLevel">The isolation level.</param>
  114. /// <param name="actionToExecute">The action to execute.</param>
  115. public static void Transaction(ConnectionStringSettings connectionStringSettings, IsolationLevel isolationLevel, Proc actionToExecute)
  116. {
  117. StartTransaction(connectionStringSettings, isolationLevel);
  118. try
  119. {
  120. using (IDbCommand command = ActiveConnection.CreateCommand())
  121. {
  122. command.Transaction = ActiveTransaction;
  123. actionToExecute(command);
  124. }
  125. CommitTransaction();
  126. }
  127. catch
  128. {
  129. RollbackTransaction();
  130. throw;
  131. }
  132. finally
  133. {
  134. DisposeTransaction();
  135. }
  136. }
  137. /// <summary>
  138. /// Disposes the transaction.
  139. /// </summary>
  140. private static void DisposeTransaction()
  141. {
  142. if (TransactionCounter <= 0)
  143. {
  144. ActiveConnection.Dispose();
  145. ActiveConnection = null;
  146. }
  147. }
  148. /// <summary>
  149. /// Rollbacks the transaction.
  150. /// </summary>
  151. private static void RollbackTransaction()
  152. {
  153. ActiveTransaction.Rollback();
  154. ActiveTransaction.Dispose();
  155. ActiveTransaction = null;
  156. TransactionCounter = 0;
  157. }
  158. /// <summary>
  159. /// Commits the transaction.
  160. /// </summary>
  161. private static void CommitTransaction()
  162. {
  163. TransactionCounter--;
  164. if (TransactionCounter == 0 && ActiveTransaction != null)
  165. {
  166. ActiveTransaction.Commit();
  167. ActiveTransaction.Dispose();
  168. ActiveTransaction = null;
  169. }
  170. }
  171. /// <summary>
  172. /// Starts the transaction.
  173. /// </summary>
  174. /// <param name="connectionStringSettings">The connection string settings to use for the transaction</param>
  175. /// <param name="isolation">The isolation.</param>
  176. private static void StartTransaction(ConnectionStringSettings connectionStringSettings, IsolationLevel isolation)
  177. {
  178. if (TransactionCounter <= 0)
  179. {
  180. TransactionCounter = 0;
  181. ActiveConnection = Connection(connectionStringSettings);
  182. ActiveTransaction = ActiveConnection.BeginTransaction(isolation);
  183. }
  184. TransactionCounter++;
  185. }
  186. /// <summary>
  187. /// Creates an open connection for a given named connection string, using the provider name
  188. /// to select the proper implementation
  189. /// </summary>
  190. /// <param name="name">The name.</param>
  191. /// <returns>The open connection</returns>
  192. public static IDbConnection Connection(string name)
  193. {
  194. ConnectionStringSettings connectionString = ConfigurationManager.ConnectionStrings[name];
  195. if (connectionString == null)
  196. throw new InvalidOperationException("Could not find connnection string: " + name);
  197. return Connection(connectionString);
  198. }
  199. /// <summary>
  200. /// Creates an open connection for a given connection string setting, using the provider
  201. /// name of select the proper implementation
  202. /// </summary>
  203. /// <param name="connectionString">ConnectionStringSetting node</param>
  204. /// <returns>The open connection</returns>
  205. public static IDbConnection Connection(ConnectionStringSettings connectionString)
  206. {
  207. if (connectionString == null)
  208. throw new InvalidOperationException("Null ConnectionStringSettings specified");
  209. if (connectionString.ProviderName == null)
  210. throw new InvalidOperationException("Null ProviderName specified");
  211. IDbConnection connection = null;
  212. string providerName = connectionString.ProviderName;
  213. if (providerName != null)
  214. {
  215. // Backwards compatibility: ProviderName could be an assembly qualified connection type name.
  216. Type connectionType = Type.GetType(providerName);
  217. if (connectionType != null)
  218. {
  219. connection = Activator.CreateInstance(connectionType) as IDbConnection;
  220. }
  221. }
  222. if (connection == null)
  223. {
  224. // ADO.NET compatible usage of provider name.
  225. connection = DbProviderFactories.GetFactory(providerName).CreateConnection();
  226. }
  227. connection.ConnectionString = connectionString.ConnectionString;
  228. connection.Open();
  229. return connection;
  230. }
  231. }
  232. }