Author Topic: ObjectId.Open obsolete  (Read 4257 times)

0 Members and 1 Guest are viewing this topic.

GUIDO ROOMS

  • Guest
ObjectId.Open obsolete
« on: June 18, 2012, 03:25:20 PM »
Good day to all,

I'm currently reading the AutoCAD .NET Developers Guide (AutoCAD 2011 version).
It says  there that using a Transaction is not obligatory: one can also work with ObjectId.Open() and ObjectId.Close()
When I look up ObjectId.Open() in arxmgd.chm, the method is not shown.
In the Visual Studio object browser, the method is shown, but when I use it in my code, I get warnings that the method is obsolete. :ugly:

Now, Can I or can't I use Open? Do I or don't I?
Any enlightenment most welcome, thanks in advance.

MexicanCustard

  • Swamp Rat
  • Posts: 705
Re: ObjectId.Open obsolete
« Reply #1 on: June 18, 2012, 03:35:24 PM »
I've never been able to get the Open or Close methods to work.  I've also had no luck opening database resident objects outside of a Transaction.  So i just start a transaction and use ObjectId.GetObject() to open any database resident object.  I'd love to hear from someone who makes it work like the Developers Guide shows.
Revit 2019, AMEP 2019 64bit Win 10

Jeff H

  • Needs a day job
  • Posts: 6144
Re: ObjectId.Open obsolete
« Reply #2 on: June 18, 2012, 03:36:15 PM »
Yes you can still use it all that means is they added a Obsolete Attribute.
 
It would be nice if they added comments like this from here to the documentation
Quote

  StartTransaction() has a huge overhead for small operations – about 100 times slower that Open and Close style for entity read operations totaling less than about 80 in a single transaction. StartOpenCloseTransaction() can be easily substituted for StartTransaction() calls, thus regaining your performance while maintaining the same code layout. I should mention that StartTransaction() really comes into it’s own on large datasets, quickly becoming 1000+ times quicker than Open and Close for write operations

Jeff H

  • Needs a day job
  • Posts: 6144
Re: ObjectId.Open obsolete
« Reply #3 on: June 18, 2012, 03:41:49 PM »
This should work just draw a line then run command and the start point should move to the orgin.
 
Code - C#: [Select]
  1.  
  2.          [CommandMethod("OpenLine")]
  3.         public void OpenLine()
  4.         {
  5.             Document doc = Application.DocumentManager.MdiActiveDocument;
  6.             Database db = doc.Database;
  7.             Editor ed = doc.Editor;
  8.             Line line = ed.GetEntity("Get Line").ObjectId.Open(OpenMode.ForWrite) as Line;
  9.             line.StartPoint = Point3d.Origin;
  10.             line.Close();
  11.         }
  12.  

GUIDO ROOMS

  • Guest
Re: ObjectId.Open obsolete
« Reply #4 on: June 18, 2012, 04:11:50 PM »
This should work just draw a line then run command and the start point should move to the orgin.
 
Code - C#: [Select]
  1.  
  2.          [CommandMethod("OpenLine")]
  3.         public void OpenLine()
  4.         {
  5.             Document doc = Application.DocumentManager.MdiActiveDocument;
  6.             Database db = doc.Database;
  7.             Editor ed = doc.Editor;
  8.             Line line = ed.GetEntity("Get Line").ObjectId.Open(OpenMode.ForWrite) as Line;
  9.             line.StartPoint = Point3d.Origin;
  10.             line.Close();
  11.         }
  12.  

Thanks for the reply.
Isn't is necessary to call line.Dispose() here?

Jeff H

  • Needs a day job
  • Posts: 6144
Re: ObjectId.Open obsolete
« Reply #5 on: June 18, 2012, 04:41:02 PM »
You could but it should not matter(If desgined the API correctly), they should do the same thing internally except you can call dispose more than once on an object.
Code - C#: [Select]
  1.  
  2.          [CommandMethod("OpenLine")]
  3.         public void OpenLine()
  4.         {
  5.             Document doc = Application.DocumentManager.MdiActiveDocument;
  6.             Database db = doc.Database;
  7.             Editor ed = doc.Editor;
  8.             Line line = ed.GetEntity("Get Line").ObjectId.Open(OpenMode.ForWrite) as Line;
  9.             line.StartPoint = Point3d.Origin;
  10.             line.Close();
  11.             if (line.IsDisposed)
  12.             {
  13.                 Application.ShowAlertDialog("Disposed");
  14.             }
  15.             else
  16.             {
  17.                 Application.ShowAlertDialog(" Not Disposed");
  18.             }
  19.             line.Dispose();
  20.         }
  21.  
It should return that it is already disposed.
 
What you can't do is the reverse(or call close twice)
This will cause a error
Code - C#: [Select]
  1.         [CommandMethod("OpenLine2")]
  2.         public void OpenLine2()
  3.         {
  4.             Document doc = Application.DocumentManager.MdiActiveDocument;
  5.             Database db = doc.Database;
  6.             Editor ed = doc.Editor;
  7.             Line line = ed.GetEntity("Get Line").ObjectId.Open(OpenMode.ForWrite) as Line;
  8.             line.StartPoint = Point3d.Origin;
  9.             line.Dispose();
  10.             line.Close();
  11.            
  12.         }
  13.  

TheMaster

  • Guest
Re: ObjectId.Open obsolete
« Reply #6 on: June 18, 2012, 05:35:21 PM »
Yes you can still use it all that means is they added a Obsolete Attribute.
 
It would be nice if they added comments like this from here to the documentation
Quote

  StartTransaction() has a huge overhead for small operations – about 100 times slower that Open and Close style for entity read operations totaling less than about 80 in a single transaction. StartOpenCloseTransaction() can be easily substituted for StartTransaction() calls, thus regaining your performance while maintaining the same code layout. I should mention that StartTransaction() really comes into it’s own on large datasets, quickly becoming 1000+ times quicker than Open and Close for write operations

Well, I have some issues with that.  :lol:

First, the overhead of 'small operations' is generally insignificant and not perceptible to a user. In other words, the fact that AcTransaction is 100 times slower than the open/close mechanism with 80 operations means little or nothing because that takes a fraction of a second either way.

Second, using the Open/Close methods directly is dangerous in certain usage contexts. One is when multiple objects are being opened simultaneously, verses serially opening and closing one object at a time. If you are opening many objects and need to keep them open simultaneously, you would need either a separate using() construct for each opened object or a separate try/finally for each open object, because if you didn't do either, some of the objects may never be closed if an exception causes the code to exit while the objects are still open.

The second context where Open()/Close() can be dangerous is when it is used with using(), and the opened object(s) are being modified. When you use a using() constrct to dispose an object that was opened via ObjectId.Open(), disposing the object causes its Close() method to be called, causing any pending changes to be committed. But with using(), the call to Dispose() will occur regardless of whether the code terminated normally or prematurely as a result of an exception.

When you use a standard transaction in the same context, the transaction's Abort() method is called by Dispose() if an exception causes the code to exit before the call to Commit() was reached, and any pending changes made to objects that were acquired via the transaction are rolled back by aborting the transaction (which is essentially the same as using UNDO/Begin/End followed by the U command).

So, for read-only access, the Open()/Close() mechanisms can be used directly and safely, but when opening and modifying objects, one must be very mindful of what happens when an open DBObject is closed as a result of a call to its Dispose() method, and whether any changes made to it should be committed or cancelled if an exception was raised while the object was open, and possibly before all changes were made to it.

The OpenCloseTransaction (StartOpenCloseTransaction()) is designed to allow the open/close mechanism to be used like a transaction, and also guarantees that if the transaction is aborted, all objects are closed via a call to their Cancel() method (rather than their Close() method). So, the OpenCloseTransaction serves two basic purposes, which is to ensure that any objects that are opened are closed when the transaction is either aborted or committed, and second, to ensure that cancel() is called on all opened objects when the transaction is aborted.

Here is a simple example that shows the dangers of using Open() and Close() directly to modify objects:

Code - C#: [Select]
  1. public static class Class1
  2. {
  3.  
  4.   public static void BuggyOpenCloseUsage()
  5.   {
  6.  
  7.     Document doc = Application.DocumentManager.MdiActiveDocument;
  8.     PromptEntityOptions peo = new PromptEntityOptions( "\nSelect a circle: ");
  9.     PromptEntityResult per = doc.Editor.GetEntity( peo );
  10.     if( per.Status != PromptStatus.Ok )
  11.       return;
  12.      
  13.     // error checking for entity type intentionally omitted
  14.    
  15.     using( Circle circle = per.ObjectId.Open( OpenMode.ForWrite ) as Circle )
  16.     {
  17.       circle.LayerId = SymbolUtilityServices.GetLayerZeroId( doc.Database );
  18.       circle.Radius = 100.0 / 0.0;  // < DivideByZeroException
  19.     }
  20.    
  21.   }
  22. }
  23.  

In the above snippet, first the circle's layer is changed to layer 0, then we intentionally cause a divide-by-zero error to simulate an exception that might occur while the object is open. When the exception causes the using() construct to call Dispose() on the opened Circle, the change to the circle's layer is committed, because DBObject.Dispose() calls DBObject.Close(), rather than DBObject.Cancel(). That means the object was left in a partially-modified state, and all changes made to it were not rolled back because transactions aren't being used.

If a standard or OpenClose transaction had been used in this same context, the same error would cause all changes made to the circle to be cancelled.


« Last Edit: June 18, 2012, 06:48:48 PM by TheMaster »

fixo

  • Guest
Re: ObjectId.Open obsolete
« Reply #7 on: June 18, 2012, 05:44:17 PM »
Perhaps easier yet to use attribute, e.g.
Code: [Select]
  [Obsolete]
        [CommandMethod("OpenLine")]
        public void OpenLine()
        {
       <  .....  >
       }

I have no errors on my end

Jeff H

  • Needs a day job
  • Posts: 6144
Re: ObjectId.Open obsolete
« Reply #8 on: June 18, 2012, 05:45:21 PM »

It would be nice if they added comments like this from here had Tony T do the documentation
Needed a fix.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: ObjectId.Open obsolete
« Reply #9 on: June 18, 2012, 05:54:05 PM »
Thanks for the comments and sharing your insight Tony.

Quote
First, the overhead of 'small operations' is generally insignificant and not perceptible to a user. In other words, the fact that AcTransaction is 100 times slower than the open/close mechanism with 80 operations means little or nothing because that takes a fraction of a second either way.

We did some testing in one of the threads here a couple of years ago.
I came to the conclusion that a consistant code style was more important than shaving a poofteenth of a microsecond from a process. 


Jeff,

Quote
It would be nice if they added comments like this from here to the documentation

I've stopped talking about the stuff that's missing from the 'documentation' ... some people suggested that I just liked to whinge and that real programmers don't need documentation anyway.

Regards
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8659
  • AKA Daniel
Re: ObjectId.Open obsolete
« Reply #10 on: June 18, 2012, 08:18:47 PM »
Quote
[Obsolete("For advanced use only. Use GetObject instead")]
public DBObject Open(OpenMode mode); 


I still use it occasionally, because I'm an advanced user  ^-^

Andrey Bushman

  • Swamp Rat
  • Posts: 864
Re: ObjectId.Open obsolete
« Reply #11 on: September 15, 2012, 12:02:12 PM »
2 TT
Thank you, TT. It is very interesting, and useful information.

2 Kerry
Quote
some people suggested that I just liked to whinge and that real programmers don't need documentation anyway.
That can talk or only those, who have never written code, or the stupid people. :( The judgement of such people has no significance.

2 Kerry
I can't to translate "poofteenth" word. Have you misprint?

Anybody tried to run TT's code? I see interesting behaviour...
AutoCAD 2013 x64 SP1.1 Enu; MS Visual Studio 2012 Enu.

I have not got error message on divide by zero, but my Circle instance was moved to 0 layer and other properties were changed - look screen below. The circle disappears. It is similar to unplanned ghost effects...

And I can't select my Circle via mouse rectangle selection. I can select it only Ctrl + A pressing key. Also AutoCAD starts to behave strange - the cursor of a mouse and a grid from time to time disappears.

If I will replace code row
Code - C#: [Select]
  1. using (AcDb.Circle circle = per.ObjectId.Open(AcDb.OpenMode.ForWrite) as AcDb.Circle)
by this:
Code - C#: [Select]
  1. using (AcDb.Circle circle = per.ObjectId.GetObject(AcDb.OpenMode.ForWrite) as AcDb.Circle)
then I'll get Fatal Error message - this is right behaviour.

And last info: ObjectId.GetObject() method not marked like Obsolete.
« Last Edit: September 15, 2012, 01:36:00 PM by Andrey »

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: ObjectId.Open obsolete
« Reply #12 on: September 15, 2012, 06:02:55 PM »
< .. >
2 Kerry
I can't to translate "poofteenth" word. Have you misprint?

< .. >

Hi Andrey,

'poofteenth' is a silly made-up word ... meant to mean a very, very small insignificant amount.

Regards
 
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.