トランザクションをネストする(.NET)

トランザクションは相互にネストできます。外側のトランザクションではルーチンで行ったすべての変更を元に戻し、内側のトランザクションでは行った変更の一部だけを元に戻すことがあります。ネストされたトランザクションを使用するときは、最も外側のトランザクションでもある最上位トランザクションから開始します。

新しいトランザクションを開始すると、前のトランザクションに追加されます。ネストされたトランザクションは、作成されたときとは逆の順序でコミットまたは中止する必要があります。したがって、3 つのトランザクションがある場合は、一番内側の 3 番目、2 番目、最後に 1 番目の順序で閉じる必要があります。最初のトランザクションを中止した場合、3 つのトランザクションが行った変更がすべて取り消されます。

次の図では、ネストされた状態のトランザクションを示します。

ネストされたトランザクションを使用してオブジェクトを作成または変更する

次の例では、3 つのトランザクションを使用して Circle オブジェクトと Line オブジェクトを作成した後、その色を変更します。円の色は 2 番目と 3 番目のトランザクションで変更されますが、3 番目のトランザクションが中止されるため、1 番目と 2 番目のトランザクションで行われた変更だけがデータベースに保存されます。また、トランザクションが作成および閉じられるときに、アクティブなトランザクションの数がコマンド ライン ウィンドウに出力されます。

VB.NET

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
        Using 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
                Using 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)
                End Using

                '' 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
        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

C#

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
        using (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
                using (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();
    }
}