Inner Transaction committed entity not available?

Inner Transaction committed entity not available?

soonhui
Advisor Advisor
1,256 Views
7 Replies
Message 1 of 8

Inner Transaction committed entity not available?

soonhui
Advisor
Advisor

Here's my code

 

   [CommandMethod(nameof(NestedTransactionsMissingEntity))]
   public static void NestedTransactionsMissingEntity()
   {
       Document doc = Application.DocumentManager.MdiActiveDocument;
       Database db = doc.Database;
       Editor ed = doc.Editor;

       using (Transaction trOuter = db.TransactionManager.StartTransaction())
       {
           // Create a line
           Line l1 = new Line(new Point3d(0, 0, 0), new Point3d(10, 0, 0));
           var btr = (BlockTableRecord)trOuter.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
           btr.AppendEntity(l1);
           trOuter.AddNewlyCreatedDBObject(l1, true);

           using (Transaction trInner1 = db.TransactionManager.StartTransaction())
           {
               var extendsInner1 = trOuter.GetAllObjects();
               var l2 = new Line(new Point3d(0 + 100, 0, 0), new Point3d(10 + 100, 0, 0));
               btr.AppendEntity(l2);
               trInner1.AddNewlyCreatedDBObject(l2, true);
               trInner1.Commit();  //after commit then l2 should be in trOuter right?
           }

           
           
           using (Transaction trInner2 = db.TransactionManager.StartTransaction())
           {
               var extentsInner2 = trOuter.GetAllObjects();  //l2 not in trOuter? ditto for trInner2
               var l3 = new Line(new Point3d(0 + 1000, 0, 0), new Point3d(10 + 1000, 0, 0));
               btr.AppendEntity(l3);
               trInner2.AddNewlyCreatedDBObject(l3, true);
               trInner2.Commit(); //after commit then l3 should be in trOuter right?
           }
           var extentsOuter = trOuter.GetAllObjects();  // l2 and l3 not in trOuter? 
           trOuter.Commit();
       }

       ed.Regen();
   }

 

You can see that the inner transaction committed entities ( l2 and l3) is not available after the fact in outer transaction. Why? 

 

And how to ensure that they are available in outer transaction?

##########

Ngu Soon Hui

##########

I'm the Benevolent Dictator for Life for MiTS Software. Read more here


I also setup Civil WHIZ in order to share what I learnt about Civil 3D
0 Likes
Accepted solutions (2)
1,257 Views
7 Replies
Replies (7)
Message 2 of 8

cuongtk2
Advocate
Advocate

You must declare them in trOuter. Line l2 = null;

0 Likes
Message 3 of 8

_gile
Consultant
Consultant

@soonhui  a écrit :

how to ensure that they are available in outer transaction?


As said in another topic, you should never use a DBObject outside of the the scope of the transaction this object has been added to because it has been disposed with this transcation.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 4 of 8

soonhui
Advisor
Advisor

@_gile , I'm not entirely sure what's your point relevance to my central question, namely

 

 var extentsOuter = trOuter.GetAllObjects();  // l2 and l3 not in trOuter? 

 

I would have expected that by that time the l2 and l3 are already in the object list in the trOuter ( because the inner transaction has been committed).  This is the impression I got when I read this:

 

T1
    ...
    T1->getAllObjects();            //only T1 objects
    T2
        ...   
        T2->getAllObjects();        //only T2 objects
        T1->getAllObjects();        //only T1 objects
        T3
            ...
            T3->getAllObjects();    //only T3 objects
            T2->getAllObjects();    //only T2 objects
            T1->getAllObjects();    //only T1 objects
        end T3
        T2->getAllObjects();        //both T2 and T3 objects
    end T2
    T1->getAllObjects();            //T1, T2 and T3 objects  
end T1
##########

Ngu Soon Hui

##########

I'm the Benevolent Dictator for Life for MiTS Software. Read more here


I also setup Civil WHIZ in order to share what I learnt about Civil 3D
0 Likes
Message 5 of 8

_gile
Consultant
Consultant

Please, stop reply in one topic to the answers given in another topic, it makes boths topics unreadable separately.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 6 of 8

soonhui
Advisor
Advisor

@_gile , I'm confining my reply to this topic only-- no cross pollination. This topic has nothing to do with variable moving outer scope ( not from me anyway), just why GetAllObjects are not really getting the objects that have been committed in the previous inner transaction. 

##########

Ngu Soon Hui

##########

I'm the Benevolent Dictator for Life for MiTS Software. Read more here


I also setup Civil WHIZ in order to share what I learnt about Civil 3D
0 Likes
Message 7 of 8

_gile
Consultant
Consultant
Accepted solution

Transaction.GetAllObjects gets the objects opened or added to this transaction.

TransactionManager.GetAllObjects gets all objects from all transactions active.

[CommandMethod(nameof(NestedTransactions))]
public static void NestedTransactions()
{
    var doc = Application.DocumentManager.MdiActiveDocument;
    var db = doc.Database;
    var ed = doc.Editor;
    var tm = db.TransactionManager;

    void TransactionObjects(string name, Transaction tr) =>
        ed.WriteMessage($"\n{name}: {string.Join(", ", tr.GetAllObjects().Cast<DBObject>().Select(e => e.GetType().Name))}");

    void TransactionManagerObjects() =>
        ed.WriteMessage($"\nTM: {string.Join(", ", tm.GetAllObjects().Cast<DBObject>().Select(e => e.GetType().Name))}");

    using (Transaction t1 = tm.StartTransaction())
    {
        var currentSpace = (BlockTableRecord)t1.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
        var line = new Line(new Point3d(-10.0, -10.0, 0.0), new Point3d(10.0, 10.0, 0.0));
        currentSpace.AppendEntity(line);
        t1.AddNewlyCreatedDBObject(line, true);

        TransactionObjects("T1", t1);
        TransactionManagerObjects();

        using (var t2 = tm.StartTransaction())
        {
            var circle = new Circle(Point3d.Origin, Vector3d.ZAxis, 10.0);
            currentSpace.AppendEntity(circle);
            t2.AddNewlyCreatedDBObject(circle, true);

            TransactionObjects("T2",t2);
            TransactionObjects("T1", t1);
            TransactionManagerObjects();

            using (var t3 = tm.StartTransaction())
            {
                var arc = new Arc(Point3d.Origin, 12.0, 0.0, Math.PI);
                currentSpace.AppendEntity(arc);
                t3.AddNewlyCreatedDBObject(arc, true);

                TransactionObjects("T3", t3);
                TransactionObjects("T2", t2);
                TransactionObjects("T1", t1);
                TransactionManagerObjects();

                t3.Commit();
            }
            TransactionObjects("T2", t2);
            TransactionManagerObjects();

            t2.Commit();
        }
        TransactionObjects("T1", t1);
        TransactionManagerObjects();

        t1.Commit();
    }
}


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 8 of 8

soonhui
Advisor
Advisor
Accepted solution

In addition to @_gile  comment, here's a code snippet and comments that illustrates the relationship between nested transaction and the Abort() function

 

        [CommandMethod(nameof(NestedTransactions))]
        public static void NestedTransactions()
        {
            var doc = Application.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;
            var tm = db.TransactionManager;

            void TransactionObjects(string name, Transaction tr) =>
                ed.WriteMessage($"\n{name}: {string.Join(", ", tr.GetAllObjects().Cast<DBObject>().Select(e => e.GetType().Name))}");

            void TransactionManagerObjects() =>
                ed.WriteMessage($"\nTM: {string.Join(", ", tm.GetAllObjects().Cast<DBObject>().Select(e => e.GetType().Name))}");

            using var t1 = tm.StartTransaction();
            var currentSpace = (BlockTableRecord)t1.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
            var line = new Line(new Point3d(-10.0, -10.0, 0.0), new Point3d(10.0, 10.0, 0.0));
            currentSpace.AppendEntity(line);
            t1.AddNewlyCreatedDBObject(line, true);

            TransactionObjects("T1", t1);
            TransactionManagerObjects();

            using (var t2 = tm.StartTransaction())
            {
                var circle = new Circle(Point3d.Origin, Vector3d.ZAxis, 10.0);
                currentSpace.AppendEntity(circle);
                t2.AddNewlyCreatedDBObject(circle, true);

                TransactionObjects("T2", t2);
                TransactionObjects("T1", t1);
                TransactionManagerObjects();

                using (var t3 = tm.StartTransaction())
                {
                    var arc = new Arc(Point3d.Origin, 12.0, 0.0, Math.PI);
                    currentSpace.AppendEntity(arc);
                    t3.AddNewlyCreatedDBObject(arc, true);

                    TransactionObjects("T3", t3);
                    TransactionObjects("T2", t2);  //still only 1 object for t2, 
                    TransactionObjects("T1", t1);
                    TransactionManagerObjects();

                    t3.Commit();
                }
                TransactionObjects("T2", t2);//still only 1 object for t2. the objects added in the nested transaction t3 ( with or without commit) is not related to t2 per se. 
                TransactionManagerObjects();  //tm has 4 objects, 2 from t1, t3 and t2 contribute one each

                t2.Abort(); //tm has only 2 objects from t1. t3 and t2 no more contributes. 
            }
            TransactionObjects("T1", t1);
            TransactionManagerObjects();

            t1.Commit();
        }
##########

Ngu Soon Hui

##########

I'm the Benevolent Dictator for Life for MiTS Software. Read more here


I also setup Civil WHIZ in order to share what I learnt about Civil 3D
0 Likes