This project is read-only.

Adding AutoComplete support to UnitOfWorkScope

Apr 2, 2009 at 5:06 PM
Hi,

After hacking NCommon to support AutoComplete functionality to UoWS, I've written an small article which you can read here: http://humm4life.blogspot.com/2009/04/adding-transaction-autocomplete-support.html

Greets.
Apr 6, 2009 at 1:47 AM
Hi Pablo,

Could you please send me a patch for NCommon containing your AutoComplete support. I'd like to include that into NCommon.

Thanks,
Ritesh
Apr 6, 2009 at 1:21 PM
Sure, Here it is.

It's against my repo which might have small differences over NCommon's trunk, but I hope this patch applies w/o problems.

Greets.

Index: C:/Dev/NW.svn/NCommon/trunk/NCommon/tests/Data/UnitOfWorkScopeTests.cs
===================================================================
--- C:/Dev/NW.svn/NCommon/trunk/NCommon/tests/Data/UnitOfWorkScopeTests.cs    (revision 236)
+++ C:/Dev/NW.svn/NCommon/trunk/NCommon/tests/Data/UnitOfWorkScopeTests.cs    (revision 237)
@@ -86,6 +86,35 @@
             mockTransaction.VerifyAllExpectations();
         }
 
+        [Test]
+        public void Disposing_AutoCommit_Scope_Does_Not_Calls_Rollback_On_Transaction()
+        {
+            var mockLocator = MockRepository.GenerateStub<IServiceLocator>();
+            var mockUOWFactory = MockRepository.GenerateMock<IUnitOfWorkFactory>();
+            var mockUOW = MockRepository.GenerateMock<IUnitOfWork>();
+            var mockTransaction = MockRepository.GenerateMock<ITransaction>();
+
+            mockLocator.Stub(x => x.GetInstance<IUnitOfWorkFactory>()).Return(mockUOWFactory);
+            mockUOWFactory.Expect(x => x.Create()).IgnoreArguments().Return(mockUOW);
+            mockUOW.Expect(x => x.BeginTransaction(IsolationLevel.ReadCommitted)).Return(mockTransaction);
+            mockUOW.Expect(x => x.Dispose());
+
+            mockTransaction.Expect(x => x.Commit());
+            mockTransaction.Expect(x => x.Dispose());
+
+            ServiceLocator.SetLocatorProvider(() => mockLocator);
+
+            using (new UnitOfWorkScope(UnitOfWorkScopeTransactionOptions.AutoComplete))
+            {
+                Assert.That(UnitOfWorkScope.HasStarted);
+            }
+
+            Assert.That(!UnitOfWorkScope.HasStarted);
+            mockUOWFactory.VerifyAllExpectations();
+            mockUOW.VerifyAllExpectations();
+            mockTransaction.VerifyAllExpectations();
+        }
+
         [Test]
         public void Commit_Scope_Calls_Flush_On_UOW_And_Commit_On_Transaction ()
         {
Index: C:/Dev/NW.svn/NCommon/trunk/NCommon/src/Data/UnitOfWorkScopeTransactionOptions.cs
===================================================================
--- C:/Dev/NW.svn/NCommon/trunk/NCommon/src/Data/UnitOfWorkScopeTransactionOptions.cs    (revision 236)
+++ C:/Dev/NW.svn/NCommon/trunk/NCommon/src/Data/UnitOfWorkScopeTransactionOptions.cs    (revision 237)
@@ -30,15 +30,19 @@
         /// exists for the current thread / request, use that transaction or create a new one. <see cref="UnitOfWorkScope"/>
         /// defaults to this option.
         /// </summary>
-        UseCompatible = 1,
+        UseCompatible = (1<<0),
         /// <summary>
         /// Specifies that the a new <see cref="UnitOfWorkScopeTransaction"/> should be created irrespective of whether
         /// a compaible transaction already exists.
         /// </summary>
-        CreateNew = 2,
+        CreateNew = (1<<2),
         /// <summary>
         /// Specifies that an ambient transaction should exists and that this context will attach to such transaction.
         /// </summary>
-        Required = 3
+        Required = (1<<3), // TODO! (pruiz)
+        /// <summary>
+        /// Specifies that UoW scope will be commited automatically at Dispose(), if it has not been rolled back previously.
+        /// </summary>
+        AutoComplete = (1<<4)
     }
 }
\ No newline at end of file
Index: C:/Dev/NW.svn/NCommon/trunk/NCommon/src/Data/UnitOfWorkScope.cs
===================================================================
--- C:/Dev/NW.svn/NCommon/trunk/NCommon/src/Data/UnitOfWorkScope.cs    (revision 236)
+++ C:/Dev/NW.svn/NCommon/trunk/NCommon/src/Data/UnitOfWorkScope.cs    (revision 237)
@@ -41,6 +41,7 @@
         private bool _disposed;
         private static Func<IsolationLevel> _isolationLevelProvider = () => IsolationLevel.ReadCommitted;
         private static readonly object _isolationLevelProviderLock = new object();
+        private bool _autocomplete = false;
         #endregion
 
         #region ctor
@@ -50,7 +51,7 @@
         /// Creates a new <see cref="UnitOfWorkScope"/> with the <see cref="IsolationLevel.Serializable"/>
         /// transaction isolation level.
         /// </summary>
-        public UnitOfWorkScope() : this(DefaultIsolationLevel, DefaultUnitOfWorkScopeTransactionOptions)
+        public UnitOfWorkScope() : this(DefaultIsolationLevel, DefaultOptions)
         {
         }
 
@@ -62,7 +63,7 @@
         /// <param name="isolationLevel">One of the values of <see cref="IsolationLevel"/> that specifies
         /// the transation isolation level the scope should use.</param>
         public UnitOfWorkScope(IsolationLevel isolationLevel)
-            : this(isolationLevel, DefaultUnitOfWorkScopeTransactionOptions)
+            : this(isolationLevel, DefaultOptions)
         {
         }
 
@@ -81,6 +82,10 @@
         public UnitOfWorkScope(IsolationLevel isolationLevel, UnitOfWorkScopeTransactionOptions transactionOptions)
         {
             _disposed = false;
+
+            if ((transactionOptions & UnitOfWorkScopeTransactionOptions.AutoComplete) != 0)
+                _autocomplete = true;
+
             _currentTransaction = UnitOfWorkScopeTransaction.GetTransactionForScope(this, isolationLevel,
                                                                                     transactionOptions);
             RegisterScope(this);
@@ -160,7 +165,7 @@
         /// </summary>
         /// <value>The default unit of work scope transaction options.</value>
         // TODO: Make this one provided by an external delegate as with DefaultIsolationLevel (pruiz)
-        public static UnitOfWorkScopeTransactionOptions DefaultUnitOfWorkScopeTransactionOptions
+        public static UnitOfWorkScopeTransactionOptions DefaultOptions
         {
             get { return UnitOfWorkScopeTransactionOptions.UseCompatible; }
         }
@@ -188,7 +193,11 @@
 
             if (_currentTransaction != null)
             {
-                _currentTransaction.Rollback(this);
+                if (_autocomplete == true)
+                    _currentTransaction.Commit(this);
+                else
+                    _currentTransaction.Rollback(this);
+
                 _currentTransaction = null;
             }
             UnRegisterScope(this);
Index: C:/Dev/NW.svn/NCommon/trunk/NCommon.LinqToSql/tests/LinqToSqlRepositoryTests.cs
===================================================================
--- C:/Dev/NW.svn/NCommon/trunk/NCommon.LinqToSql/tests/LinqToSqlRepositoryTests.cs    (revision 236)
+++ C:/Dev/NW.svn/NCommon/trunk/NCommon.LinqToSql/tests/LinqToSqlRepositoryTests.cs    (revision 237)
@@ -550,7 +550,7 @@
             {
                 using (var tr = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.RequiresNew))
                 {
-                    using (var scope = new UnitOfWorkScope(UnitOfWorkScopeTransactionOptions.Required))
+                    using (var scope = new UnitOfWorkScope())
                     {
                         var customerRepository = new LinqToSqlRepository<Customer>();
                         var recordCheckResult = (from cust in customerRepository
@@ -593,7 +593,7 @@
                 {
                     using (var tr = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.RequiresNew))
                     {
-                        using (var scope = new UnitOfWorkScope(UnitOfWorkScopeTransactionOptions.Required))
+                        using (var scope = new UnitOfWorkScope())
                         {
                             var customerRepository = new LinqToSqlRepository<Customer>();
                             var recordCheckResult = (from cust in customerRepository