Using transactions when managing documents

This chapter explains how to work with transactions in Kentico CMS API. Transactions are usually used to ensure database consistency.

 

Native transactions

 

Kentico CMS uses SQL transactions to ensure the system database consistency when performing complex operations consisting of multiple steps. In such cases the whole operation forms a single block of SQL commands that can be rolled back when an error occurs or committed if the complete operation was successful. Transaction handling is provided by CMS.DataEngine library, in the  GeneralConnection class.

 

Please note that you should always use single connection for every operation within the open transaction to avoid deadlocks.

 

The transactions flow in Kentico CMS looks like this:

 

clip0758

 

Please note: Always pass the existing connection as a method parameter if you call the method that uses DB access within transaction.

 

 

Example

 

Please use following example as a template in all the methods that work with transactions:

 

[C#]

 

using CMS.DataEngine;

using CMS.TreeEngine;

using CMS.FileManager;

using CMS.WorkflowEngine;

 

/// <summary>

/// Sample method

/// </summary>

/// <param name="conn">Data connection to use</param>

public void DoSomethingInTransaction(GeneralConnection conn)

{

bool closeConnectionAtTheEnd = false;

bool commitTransactionAtTheEnd = false;

 

try

{

   // Open connection is necessary

   if (!conn.DataConnection.IsOpen())

   {

     conn.DataConnection.Open();

     closeConnectionAtTheEnd = true;

   }

   // Start transaction if necessary

   if (!conn.DataConnection.IsTransaction())

   {

     conn.DataConnection.BeginTransaction();

     commitTransactionAtTheEnd = true;

   }

 

 

   // --- HERE YOU CAN USE YOUR DATABASE ACCESS CODE LIKE: ----

   DataSet ds = conn.ExecuteQuery("cms.user.selectall", null, null, null);

 

   // --- IF YOU NEED TO USE TREEPROVIDER, ALWAYS INSTATIATE IT WITH EXISTING CONNECTION

   TreeProvider tree = new TreeProvider(null, conn);

 

   // --- ALWAYS USE METHOD OVERRIDES THAT USE CONNECTION (TREEPROVIDER) PARAMETER ---

   AttachmentInfo ai = DocumentHelper.GetAttachment(Guid.NewGuid(), 1, tree);

 

 

   // Commit transaction if necessary

   if (commitTransactionAtTheEnd)

   {

     conn.DataConnection.CommitTransaction();

     commitTransactionAtTheEnd = false;

   }

}

catch (Exception ex)

{

   // Rollback transaction if necessarry

   if (commitTransactionAtTheEnd)

   {

     conn.DataConnection.RollbackTransaction();

     commitTransactionAtTheEnd = false;

   }

   throw ex;

}

finally

{

   // Close the connection if necessarry

   if (closeConnectionAtTheEnd)

   {

     conn.DataConnection.Close();

     closeConnectionAtTheEnd = false;

   }

}

}

 

You may also work with TreeProvider class instead of connection object. In that case, use its Connection property the same way like the GeneralConnection in this example and use the same connection object in all operations inside the transaction.