.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Is the same Entity reference valid across nested transaction?

10 REPLIES 10
SOLVED
Reply
Message 1 of 11
soonhui
268 Views, 10 Replies

Is the same Entity reference valid across nested transaction?

Is the same Entity reference valid across nested transaction, all the time? I have code as such ( where I reuse not just the ObjectId of the line Entity, but also the entity itself).

 

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

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

                // Inner transaction 1: Change color
                using (Transaction trInner1 = db.TransactionManager.StartTransaction())
                {
                    line.ColorIndex = 1; // Red
                    trInner1.Commit();
                }

                // Inner transaction 2: Change layer
                using (Transaction trInner2 = db.TransactionManager.StartTransaction())
                {
                    line.Layer = "A-BLDG"; 
                    trInner2.Commit();
                }

                trOuter.Commit();
            }

            ed.Regen();
        }

 

It works, but I'm not sure whether it's always safe to do this? or I have to use ObjectId and get the actual entity from the reigning Transaction ( since ObjectId is the same within the lifetime of the drawing)?

##########

Ngu Soon Hui

##########

I'm the Benevolent Dictator for Life for MiTS Software.

Read more at here

10 REPLIES 10
Message 2 of 11
_gile
in reply to: soonhui

Hi,

The 'line' entity is available within the whole scope of the 'trOuter' transaction including nested transactions and methods called within this scope.

So, yes it is safe to do this (even nested transactions are absolutely useless in this example).

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 3 of 11
soonhui
in reply to: soonhui

@_gile , I admit that I ask a useless question.

 

A more interesting question is, if I create a new Entity in the trInner1 ( let's call it l1), I can access l1 and use it normally in trInner2? Or I have to use l1.ObjectId to retriev back the same entity in trInner2?

##########

Ngu Soon Hui

##########

I'm the Benevolent Dictator for Life for MiTS Software.

Read more at here

Message 4 of 11
cuongtk2
in reply to: soonhui

Refer to local scope.

Message 5 of 11
_gile
in reply to: soonhui


@soonhui  a écrit :

A more interesting question is, if I create a new Entity in the trInner1 ( let's call it l1), I can access l1 and use it normally in trInner2? Or I have to use l1.ObjectId to retriev back the same entity in trInner2?


Same reply as upper, 'l1' is only available in the scope of 'trInner1', in other words, between the openning curly bracket following the using statement where 'trinner1' is initialized and the corresponding closing curly bracket.

When we add a newly created onject to a transaction (using AddNewlyCreatedDBObject) this newly created object will be automatically disposed as soon as the transaction is disposed.

using (Transaction trInner1 = db.TransactionManager.StartTransaction())
{
    // Create a line
    Line l1 = new Line(new Point3d(0, 0, 0), new Point3d(10, 0, 0));
    var btr = (BlockTableRecord)trInner1.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
    btr.AppendEntity(l1);
    // Add the newly created line to the transaction
    trInner1.AddNewlyCreatedDBObject(l1, true);
    trInner1.Commit();
} // <- Both 'trInner1' and 'l1' are disposed at the end of the using statement.

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 6 of 11
soonhui
in reply to: soonhui

@cuongtk2 , @_gile , so if I move the declaration of l1 to outer scope ( or if I wrap the above code in a method and pass back l1 to the outer scope), then I can use  l1 outer scope as usual, no problem?

##########

Ngu Soon Hui

##########

I'm the Benevolent Dictator for Life for MiTS Software.

Read more at here

Message 7 of 11
_gile
in reply to: soonhui


@soonhui  a écrit :

@cuongtk2 , @_gile , so if I move the declaration of l1 to outer scope ( or if I wrap the above code in a method and pass back l1 to the outer scope), then I can use  l1 outer scope as usual, no problem?


No, despite the 'l1' variable is accessible, its value (the entity) has been disposed.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 8 of 11
cuongtk2
in reply to: soonhui

 

 using (var trOuter = db.TransactionManager.StartTransaction())
 {
     Line l1 = null;
     using (Transaction trInner1 = db.TransactionManager.StartTransaction())
     {
         // Create a line
         l1 = new Line(new Point3d(0, 0, 0), new Point3d(10, 0, 0));
         var btr = (BlockTableRecord)trInner1.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
         btr.AppendEntity(l1);
         // Add the newly created line to the transaction
         trInner1.AddNewlyCreatedDBObject(l1, true);
         trInner1.Commit();
     }
     // change l1 EndPoint
     l1.EndPoint = new Point3d(5, 0, 0);
     trOuter.Commit();
     // l1.length = 5.0
 }

 

Message 9 of 11
_gile
in reply to: cuongtk2

@cuongtk2 

The code you posted is not safe because 'l1' is disposed withe the transaction (line #13) and setting l1.EndPoint after that (line # 15) may crash AutoCAD (it depends on when the garbage collection occurs).

One more time, the rule is: never use a DBObject outside of the the scope of the transaction this object has been opened with or added to.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 10 of 11
ActivistInvestor
in reply to: _gile


@_gile wrote:

@cuongtk2 

The code you posted is not safe because 'l1' is disposed withe the transaction (line #13) and setting l1.EndPoint after that (line # 15) may crash AutoCAD (it depends on when the garbage collection occurs).

One more time, the rule is: never use a DBObject outside of the the scope of the transaction this object has been opened with or added to.


Hi @_gile . As I'm sure you know, I have cited the same advise you offer above many times, however that is generally related to outermost transactions only.

 

Nested transactions are a different kind of animal. In fact, @cuongtk2 's code is perfectly safe, as explained by @artc2 in the thread I linked to above. 

Message 11 of 11
_gile
in reply to: ActivistInvestor

@ActivistInvestor Thanks. I'm always glad to learn a new thing.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

AutoCAD Inside the Factory


Autodesk Design & Make Report