Transaction Classes

Transaction Classes

All three transaction objects share some common methods:

Table 51: Common Transaction Object Methods

Method

Description

Start

Will start the context

Commit

Ends the context and commits all changes to the document

Rollback

Ends the context and discards all changes to the document

GetStatus

Returns the current status of the transaction object

In addition to the GetStatus() method returning the current status, the Start, Commit and RollBack methods also return a TransactionStatus indicating whether or not the method was successful. Available TransactionStatus values include:

Table 52: TransactionStatus values

Status

Description

Uninitialized

The initial value after object is instantiated; the context has not started yet

Started

Transaction object has successfully started (Start was called)

RolledBack

Transaction object was successfully rolled back (Rollback was called)

Committed

Transaction object was successfully committed (Commit was called)

Pending

Transaction object was attempted to be either submitted or rolled back, but due to failures that process could not be finished yet and is waiting for the end-user's response (in a modeless dialog). Once the failure processing is finished, the status will be automatically updated (to either Committed or RolledBack status).

Transaction

A transaction is a context required in order to make any changes to a Revit model. Only one transaction can be open at a time; nesting is not allowed. Each transaction must have a name, which will be listed on the Undo menu in Revit once a transaction is successfully committed.

Code Region 23-1: Using transactions

public void CreatingSketch(UIApplication uiApplication)
{
    Autodesk.Revit.DB.Document document = uiApplication.ActiveUIDocument.Document;
    Autodesk.Revit.ApplicationServices.Application application = uiApplication.Application;

    // Create a few geometry lines. These lines are transaction (not in the model),
    // therefore they do not need to be created inside a document transaction.
    XYZ Point1 = XYZ.Zero;
    XYZ Point2 = new XYZ(10, 0, 0);
    XYZ Point3 = new XYZ(10, 10, 0);
    XYZ Point4 = new XYZ(0, 10, 0);

    Line geomLine1 = Line.CreateBound(Point1, Point2);
    Line geomLine2 = Line.CreateBound(Point4, Point3);
    Line geomLine3 = Line.CreateBound(Point1, Point4);

    // This geometry plane is also transaction and does not need a transaction
    XYZ origin = XYZ.Zero;
    XYZ normal = new XYZ(0, 0, 1);
    Plane geomPlane = application.Create.NewPlane(normal, origin);

    // In order to a sketch plane with model curves in it, we need
    // to start a transaction because such operations modify the model.

    // All and any transaction should be enclosed in a 'using'
    // block or guarded within a try-catch-finally blocks
    // to guarantee that a transaction does not out-live its scope.
    using (Transaction transaction = new Transaction(document))
    {
        if (transaction.Start("Create model curves") == TransactionStatus.Started)
        {
            // Create a sketch plane in current document
            SketchPlane sketch = SketchPlane.Create(document,geomPlane);

            // Create a ModelLine elements using the geometry lines and sketch plane
            ModelLine line1 = document.Create.NewModelCurve(geomLine1, sketch) as ModelLine;
            ModelLine line2 = document.Create.NewModelCurve(geomLine2, sketch) as ModelLine;
            ModelLine line3 = document.Create.NewModelCurve(geomLine3, sketch) as ModelLine;

            // Ask the end user whether the changes are to be committed or not
            TaskDialog taskDialog = new TaskDialog("Revit");
            taskDialog.MainContent = "Click either [OK] to Commit, or [Cancel] to Roll back the transaction.";
            TaskDialogCommonButtons buttons = TaskDialogCommonButtons.Ok | TaskDialogCommonButtons.Cancel;
            taskDialog.CommonButtons = buttons;

            if (TaskDialogResult.Ok == taskDialog.Show())
            {
                // For many various reasons, a transaction may not be committed
                // if the changes made during the transaction do not result a valid model.
                // If committing a transaction fails or is canceled by the end user,
                // the resulting status would be RolledBack instead of Committed.
                if (TransactionStatus.Committed != transaction.Commit())
                {
                    TaskDialog.Show("Failure", "Transaction could not be committed");
                }
            }
            else
            {
                transaction.RollBack();
            }
        }
    }
}

SubTransaction

A SubTransaction can be used to enclose a set of model-modifying operations. Sub-transactions are optional. They are not required in order to modify the model. They are a convenience tool to allow logical splitting of larger tasks into smaller ones. Sub-transactions can only be created within an already opened transaction and must be closed (either committed or rolled back) before the transaction is closed (committed or rolled back). Unlike transactions, sub-transaction may be nested, but any nested sub-transaction must be closed before the enclosing sub-transaction is closed. Sub-transactions do not have a name, for they do not appear on the Undo menu in Revit.

TransactionGroup

TransactionGroup allows grouping together several independent transactions, which gives the owner of a group an opportunity to address many transactions at once. When a transaction group is to be closed, it can be rolled back, which means that all previously committed transactions belonging to the group will be rolled back. If not rolled back, a group can be either committed or assimilated. In the former case, all committed transactions (within the group) will be left as they were. In the later case, transactions within the group will be merged together into one single transaction that will bear the group's name.

A transaction group can only be started when there is no transaction open yet, and must be closed only after all enclosed transactions are closed (rolled back or committed). Transaction groups can be nested, but any nested group must be closed before the enclosing group is closed. Transaction groups are optional. They are not required in order to make modifications to a model.

The following example shows the use of a TransactionGroup to combine two separate Transactions using the Assimilate() method. The following code will result in a single Undo item added to the Undo menu with the name "Level and Grid".

Code Region 23-2: Combining multiple transactions into a TransactionGroup

public void CompoundOperation(Autodesk.Revit.DB.Document document)
{
    // All and any transaction group should be enclosed in a 'using' block or guarded within
    // a try-catch-finally blocks to guarantee that the group does not out-live its scope.
    using (TransactionGroup transGroup = new TransactionGroup(document, "Level and Grid"))
    {
        if (transGroup.Start() == TransactionStatus.Started)
        {
            // We are going to call two methods, each having its own local transaction.
            // For our compound operation to be considered successful, both the individual
            // transactions must succeed. If either one fails, we will roll our group back,
            // regardless of what transactions might have already been committed.

            if (CreateLevel(document, 25.0) && CreateGrid(document, new XYZ(0,0,0), new XYZ(10,0,0)))
            {
                // The process of assimilating will merge the two (or any number of) committed
                // transaction together and will assign the grid's name to the one resulting transaction,
                // which will become the only item from this compound operation appearing in the undo menu.
                transGroup.Assimilate();
            }
            else
            {
                // Since we could not successfully finish at least one of the individual
                // operation, we are going to roll the entire group back, which will
                // undo any transaction already committed while this group was open.
                transGroup.RollBack();
            }
        }
    }
}

public bool CreateLevel(Autodesk.Revit.DB.Document document, double elevation)
{
    // All and any transaction should be enclosed in a 'using'
    // block or guarded within a try-catch-finally blocks
    // to guarantee that a transaction does not out-live its scope.
    using (Transaction transaction = new Transaction(document, "Creating Level"))
    {
        // Must start a transaction to be able to modify a document
               
        if( TransactionStatus.Started == transaction.Start())
        {
            if (null != document.Create.NewLevel(elevation))
            {
                // For many various reasons, a transaction may not be committed
                // if the changes made during the transaction do not result a valid model.
                // If committing a transaction fails or is canceled by the end user,
                // the resulting status would be RolledBack instead of Committed.
                return (TransactionStatus.Committed == transaction.Commit());
            }

            // For we were unable to create the level, we will roll the transaction back
            // (although on this simplified case we know there weren't any other changes)

            transaction.RollBack();
        }
    }
    return false;
}

public bool CreateGrid(Autodesk.Revit.DB.Document document, XYZ p1, XYZ p2)
{
    // All and any transaction should be enclosed in a 'using'
    // block or guarded within a try-catch-finally blocks
    // to guarantee that a transaction does not out-live its scope.
    using (Transaction transaction = new Transaction(document, "Creating Grid"))
    {
        // Must start a transaction to be able to modify a document
        if (TransactionStatus.Started == transaction.Start())
        {
            // We create a line and use it as an argument to create a grid
            Line gridLine = Line.CreateBound(p1, p2);
                 
            if ((null != gridLine) && (null != document.Create.NewGrid(gridLine)))
            {
                if (TransactionStatus.Committed == transaction.Commit())
                {
                return true;
                }
            }

            // For we were unable to create the grid, we will roll the transaction back
            // (although on this simplified case we know there weren't any other changes)

            transaction.RollBack();
        }
    }
    return false;
}