Friday, February 16, 2007

We are working hard on our upcoming 1.6 release and we are very excited about it. EntitySpaces 1.6 is going to deliver a truly amazing set of features. The EntitySpaces esTransactionScope class is being greatly enhanced to provide even more power and flexibility for your enterprise level development projects. Before we begin, however, a little background is in order.

Before the Microsoft .NET Framework was released most of my development (Mike) involved creating COM+ object models on top of SQL Server using C++. These objects models would then be consumed by VBScript programmers to create corporate websites. This might date me a little but I was there when OLE 1.0 was released. Later, when NT Service Pack 4 was released MTS became a serious technology and it really got interesting. Finally, it was all rolled into Windows NT itself as COM+. I designed many large Distributed Network Architectures (DNA) using COM+ to protect several concurrent SQL Servers / MSMQ servers which then delivered packets to EIA brokers, all in a single distributed transaction. It was the stuff dreams are made of. If it's one thing I know, it's that the transaction is the heart of any architecture and should be front and center in your ORM solution. In the end, before the dawn of .NET, I was using the Active Template Library (ATL) in combination with the Standard Template Library (STL) to create incredibly high performing distributed network architectures. Indeed, ATL and STL in the right hands was a deadly weapon.

When Microsoft .NET was released I created dOOdads (back in the leather helmet days). I used COM+ as my inspiration. There was no way I was going to do what most of the industry was doing and that was passing Transactions and Connections around all throughout my API, it had to be seamless. Thus, I used Thread Local Storage (TLS) and stuffed the Transaction into a slot on the thread. Then, down low in the architecture the base classes simply enlisted into the transaction, if there was an ongoing transaction. To the programmer it's magic.

If you are familiar with the TransactionScope class in the Microsoft .NET System.Transactions namespace then you will be very comfortable with the EntitySpaces esTransactionScope class. The really cool thing about the .NET TransactionScope is how it uses the "using" syntax to control the transactions "scope" or lifetime. EntitySpaces runs fine using the .NET TransactionScope, however the System.Transactions.TransactionScope class can add some significant overhead if you are not in need of distributed transactions. The .NET TransactionScope is a truly amazing work of art itself in the way it can promote local lightweight transactions to distributed transactions when another resource is enlisted. However, there is a certain amount of overhead when using the .NET TransactionScope class and most hosting companies will not allow you use the .NET TransactionScope class as it enlists the Distributed Transaction Coordinator (DTS). 

In summary, the esTransactionScope class uses Thread Local Storage (TLS) to avoid intrusion and takes advantage of the the "using" syntax to control a transactions "lifetime". The esTransactionScope fills a very noticeable void in the Microsoft .NET Framework, and that is an elegant solution for ADO.NET connection based transactions.

Currently, in our 1.5 release esTransactionScope can be nested as follows:

using (esTransactionScope scope = new esTransactionScope())
{
    Employees emp = new Employees();
    emp.LoadByPrimaryKey(1);
    emp.FirstName = "Joe";
    emp.Save();

    Customers cust = new Customers();
    // ...
    cust.Save();

    scope.Complete();
}


In the code above, both the Employees and Customer Save methods also use the esTransactionScope, they can be nested just fine. Only when the final outer scope.Complete() is executed is the transaction truly committed. However, there are times when you might want to write to a SQL table during an exception possibly caused by a rolled back transaction, for instance, to record the callstack information. Or you might just otherwise need to break out of an ongoing transaction. You might even want to have a nested transaction that acts as it's own root transaction much like a COM+ requires new transaction. We have added this granular level of control in the enhanced 1.6 esTransactionScope class. The ability to nest all of these different types at your leisure greatly enhances your power to accomplish what you need to with EntitySpaces. In our 1.6 release the esTransactionScope accepts an optional parameter on it's constructor, and that is the esTransactionScopeOption enum.

public enum esTransactionScopeOption
{
    // Summary:
    //     A transaction is required by the scope. It uses an ongoing transaction if
    //     one already exists. Otherwise, it creates a new transaction before entering
    //     the scope. This is the default value.
    Required = 0,
    //
    // Summary:
    //     A new transaction is always created for the scope.
    RequiresNew = 1,
    //
    // Summary:
    //     Any ongoing transaction is suppressed when creating the scope. All
    //     operations within the scope are done without a transaction.
    Suppress = 2,
}


The following code snippet shows how you can nest and control the transactions at a very granular level. However, our recommendation is to run with Required for all nested transactions. You must be careful not to create deadlocks. The default isolation level of esTransactionScope is Serializable, which offers the most protection.

using (esTransactionScope rootTrans1 = new esTransactionScope())
{
    using (esTransactionScope noTrans = new esTransactionScope(esTransactionScopeOption.Suppress))
    {
        // Anything done in here runs without a transaction because of the "Suppress"
        esUtility util = new esUtility();
        int count = (int)util.ExecuteScalar(esQueryType.Text, "Select Count(*) From Employees");

        using (esTransactionScope scope = new esTransactionScope())
        {
            // This transaction scope uses the default is Required, therefore it enlists in "rootTrans1"
            Employees emp = new Employees();
            emp.LoadByPrimaryKey(1);
            emp.FirstName = "Joe";
            emp.Save();

            using (esTransactionScope rootTrans2 = new esTransactionScope(esTransactionScopeOption.RequiresNew))
            {
                // This is a new root transaction and doesn't partake in "rootTrans1"
                Employees emp1 = new Employees();
                emp1.LoadByPrimaryKey(2);
                emp1.FirstName = "Sam";
                emp1.Save();

                // Since this was a RequiresNew tranaction, the true commit is done here
                rootTrans2.Complete();
            }

            // Doesn't commit yet, as "rootTrans1" is the root
            scope.Complete();
        }

        noTrans.Complete();
    }

    // Commits the rootTrans1 and any nested transactions
    rootTrans1.Complete();
}

If you were paying attention to the above code you might have noticed the new esUtility class, this class allows you to execute any SQL without using a specific EntitySpaces Collection or Entity, thus the name, esUtility. This is just a sneak peak and we will post many more of these to give you insights into our next release.


The EntitySpaces Team
--
EntitySpaces LLC
Persistence Layer and Business Objects for Microsoft .NET 2.0
http://www.entityspaces.net/

posted on Friday, February 16, 2007 9:52:19 PM (Eastern Standard Time, UTC-05:00)  #    Comments [3]