Transactions can be nested one inside another. You might have an outer transaction to undo all the changes made by your routine and inner transactions to undo just portions of the changes made. When you work with nested transactions, you start with a top transaction which is also the outer most transaction.
As you start new transactions, they are added into the previous transaction. Nested transactions must be committed or aborted in the opposite order in which they are created. So if you have three transactions, you must close the third or innermost one before the second and finally the first. If you abort the first transaction, the changes made by all three transactions is undone.
The following illustration shows how transactions appear when nested.
Use nested transactions to create and modify objects
The following example demonstrates using three transactions to create a Circle and Line object, and then change their colors. The color of the circle is changed in the second and third transaction, but since the third transaction is aborted only the changes made in the first and second transactions are saved to the database. Additionally, the number of active transactions is printed in the Command Line window as they are created and closed.
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.EditorInput
<CommandMethod("NestedTransactions")> _
Public Sub NestedTransactions()
'' Get the current document and database
Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
Dim acCurDb As Database = acDoc.Database
'' Create a reference to the Transaction Manager
Dim acTransMgr As Autodesk.AutoCAD.DatabaseServices.TransactionManager
acTransMgr = acCurDb.TransactionManager
'' Create a new transaction
Using acTrans1 As Transaction = acTransMgr.StartTransaction()
'' Print the current number of active transactions
acDoc.Editor.WriteMessage(vbLf & "Number of transactions active: " & _
acTransMgr.NumberOfActiveTransactions.ToString())
'' Open the Block table for read
Dim acBlkTbl As BlockTable
acBlkTbl = acTrans1.GetObject(acCurDb.BlockTableId, OpenMode.ForRead)
'' Open the Block table record Model space for write
Dim acBlkTblRec As BlockTableRecord
acBlkTblRec = acTrans1.GetObject(acBlkTbl(BlockTableRecord.ModelSpace), _
OpenMode.ForWrite)
'' Create a circle with a radius of 3 at 5,5
Dim acCirc As Circle = New Circle()
acCirc.Center = New Point3d(5, 5, 0)
acCirc.Radius = 3
'' Add the new object to Model space and the transaction
acBlkTblRec.AppendEntity(acCirc)
acTrans1.AddNewlyCreatedDBObject(acCirc, True)
'' Create the second transaction
Using acTrans2 As Transaction = acTransMgr.StartTransaction()
acDoc.Editor.WriteMessage(vbLf & "Number of transactions active: " & _
acTransMgr.NumberOfActiveTransactions.ToString())
'' Change the circle's color
acCirc.ColorIndex = 5
'' Get the object that was added to Transaction 1 and set it to the color 5
Dim acLine As Line = New Line(New Point3d(2, 5, 0), New Point3d(10, 7, 0))
acLine.ColorIndex = 3
'' Add the new object to Model space and the transaction
acBlkTblRec.AppendEntity(acLine)
acTrans2.AddNewlyCreatedDBObject(acLine, True)
'' Create the third transaction
Using acTrans3 As Transaction = acTransMgr.StartTransaction()
acDoc.Editor.WriteMessage(vbLf & "Number of transactions active: " & _
acTransMgr.NumberOfActiveTransactions.ToString())
'' Change the circle's color
acCirc.ColorIndex = 3
'' Update the display of the drawing
acDoc.Editor.WriteMessage(vbLf)
acDoc.Editor.Regen()
'' Request to keep or discard the changes in the third transaction
Dim pKeyOpts As PromptKeywordOptions = New PromptKeywordOptions("")
pKeyOpts.Message = vbLf & "Keep color change "
pKeyOpts.Keywords.Add("Yes")
pKeyOpts.Keywords.Add("No")
pKeyOpts.Keywords.Default = "No"
pKeyOpts.AllowNone = True
Dim pKeyRes As PromptResult = acDoc.Editor.GetKeywords(pKeyOpts)
If pKeyRes.StringResult = "No" Then
'' Discard the changes in transaction 3
acTrans3.Abort()
Else
'' Save the changes in transaction 3
acTrans3.Commit()
End If
'' Dispose the transaction
End Using
acDoc.Editor.WriteMessage(vbLf & "Number of transactions active: " & _
acTransMgr.NumberOfActiveTransactions.ToString())
'' Keep the changes to transaction 2
acTrans2.Commit()
End Using
acDoc.Editor.WriteMessage(vbLf & "Number of transactions active: " & _
acTransMgr.NumberOfActiveTransactions.ToString())
'' Keep the changes to transaction 1
acTrans1.Commit()
End Using
End Sub
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;
[CommandMethod("NestedTransactions")]
public static void NestedTransactions()
{
// Get the current document and database
Document acDoc = Application.DocumentManager.MdiActiveDocument;
Database acCurDb = acDoc.Database;
// Create a reference to the Transaction Manager
Autodesk.AutoCAD.DatabaseServices.TransactionManager acTransMgr;
acTransMgr = acCurDb.TransactionManager;
// Create a new transaction
using (Transaction acTrans1 = acTransMgr.StartTransaction())
{
// Print the current number of active transactions
acDoc.Editor.WriteMessage("\nNumber of transactions active: " +
acTransMgr.NumberOfActiveTransactions.ToString());
// Open the Block table for read
BlockTable acBlkTbl;
acBlkTbl = acTrans1.GetObject(acCurDb.BlockTableId,
OpenMode.ForRead) as BlockTable;
// Open the Block table record Model space for write
BlockTableRecord acBlkTblRec;
acBlkTblRec = acTrans1.GetObject(acBlkTbl[BlockTableRecord.ModelSpace],
OpenMode.ForWrite) as BlockTableRecord;
// Create a circle with a radius of 3 at 5,5
Circle acCirc = new Circle();
acCirc.Center = new Point3d(5, 5, 0);
acCirc.Radius = 3;
// Add the new object to Model space and the transaction
acBlkTblRec.AppendEntity(acCirc);
acTrans1.AddNewlyCreatedDBObject(acCirc, true);
// Create the second transaction
using (Transaction acTrans2 = acTransMgr.StartTransaction())
{
acDoc.Editor.WriteMessage("\nNumber of transactions active: " +
acTransMgr.NumberOfActiveTransactions.ToString());
// Change the circle's color
acCirc.ColorIndex = 5;
// Get the object that was added to Transaction 1 and set it to the color 5
Line acLine = new Line(new Point3d(2, 5, 0), new Point3d(10, 7, 0));
acLine.ColorIndex = 3;
// Add the new object to Model space and the transaction
acBlkTblRec.AppendEntity(acLine);
acTrans2.AddNewlyCreatedDBObject(acLine, true);
// Create the third transaction
using (Transaction acTrans3 = acTransMgr.StartTransaction())
{
acDoc.Editor.WriteMessage("\nNumber of transactions active: " +
acTransMgr.NumberOfActiveTransactions.ToString());
// Change the circle's color
acCirc.ColorIndex = 3;
// Update the display of the drawing
acDoc.Editor.WriteMessage("\n");
acDoc.Editor.Regen();
// Request to keep or discard the changes in the third transaction
PromptKeywordOptions pKeyOpts = new PromptKeywordOptions("");
pKeyOpts.Message = "\nKeep color change ";
pKeyOpts.Keywords.Add("Yes");
pKeyOpts.Keywords.Add("No");
pKeyOpts.Keywords.Default = "No";
pKeyOpts.AllowNone = true;
PromptResult pKeyRes = acDoc.Editor.GetKeywords(pKeyOpts);
if (pKeyRes.StringResult == "No")
{
// Discard the changes in transaction 3
acTrans3.Abort();
}
else
{
// Save the changes in transaction 3
acTrans3.Commit();
}
// Dispose the transaction
}
acDoc.Editor.WriteMessage("\nNumber of transactions active: " +
acTransMgr.NumberOfActiveTransactions.ToString());
// Keep the changes to transaction 2
acTrans2.Commit();
}
acDoc.Editor.WriteMessage("\nNumber of transactions active: " +
acTransMgr.NumberOfActiveTransactions.ToString());
// Keep the changes to transaction 1
acTrans1.Commit();
}
}