.NET

.NET

Reply
*Glenn Ryan
Message 11 of 18 (483 Views)

Re: Transactions, purge and eWasErased...

08-03-2005 05:50 AM in reply to: *Glenn Ryan
There's the rub...as far as I know, defaul indexers only take one argument
in the .net universe and that is the 'index' to return...?

"Tony Tanzillo" wrote in message
news:4918106@discussion.autodesk.com...
Exposing getAt() might help for cases where you want
deleted records, but another way would be to expose
a boolean property on the SymbolTable wrapper, that
would control if erased records are returned by the
default indexer.

Regardless, the current behavior is clearly a potential
source of some very nasty bugs.

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2004/2005/2006
http://www.acadxtabs.com

"Glenn Ryan" wrote in message
news:4918031@discussion.autodesk.com...
Tony,

I had already come to the same conclusion and had adjusted my code
acccordingly - thanks for the confirmation.
Thinking out loud, I know the *preferred* way in .net is to have a default
indexer [], but it would be nice to have AcDbSymbolTable::getAt
exposed directly as well, because, as you mentioned, it effects ALL derived
classes as well.

Cheers,
Glenn.

"Tony Tanzillo" wrote in message
news:4917010@discussion.autodesk.com...
The fact that you're getting an eDuplicateRecord error
serves to confirm that the problem is what I said it
was initially, which is that the default indexer for the
SymbolTable managed wrapper class, is incorrectly (IMO)
calling AcDbSymbolTable::getAt() with the third argument
set to true. That will cause it to return the first matching
entry, even if it is erased.

Hence, that effectively makes the default indexer for the
SymbolTable and all derived classes, useless (unless you
want it to return deleted symbol table records, which is
generally not the case).

The only way around it is to iterate over the entire layer
table, to locate the entry with the specified name.

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2004/2005/2006
http://www.acadxtabs.com

"Glenn Ryan" wrote in message
news:4916851@discussion.autodesk.com...
Tony,

If you follow these steps, with the revised code below, you will get the
eDuplicateRecord error:

1. Start blank new drawing.
2. Run code.
3. Set layer 0 current.
4. Purge
5. Run code.
6. Run code.

Revised code (the only thing that has changed is the TRUE branch of the main
IF statement):

[CommandMethod("LayerTest")]
public void test() // This method can have any name
{
Document pDoc = AcadApp.DocumentManager.MdiActiveDocument;
// Get a pointer to the current doc's dbase...
Database pDb = pDoc.Database;
// While we're at it, get a pointer to the editor...
Editor pEd = pDoc.Editor;
// Our 'test' layer name...
string layerName = "Test";
// Our test layer's objectIdnl

ObjectId layerId = ObjectId.Null;
// Kick off a transaction in the current dbase...
using (Transaction pTr = pDb.TransactionManager.StartTransaction())
{
try
{
// Try and open the layer table for write...
LayerTable pLayerTable = (LayerTable)pTr.GetObject(pDb.LayerTableId,
OpenMode.ForRead);
// Does it contain our layer?
if (pLayerTable.Has(layerName))
{
layerId = pLayerTable[layerName];
if (layerId.IsErased)
{
LayerTableRecord pExLtr = (LayerTableRecord)pTr.GetObject(layerId,
OpenMode.ForWrite, true);
pExLtr.Erase(false);
}

}
else // Nope, so create it...
{
LayerTableRecord pNewLTR = new LayerTableRecord();
// Set the name...
pNewLTR.Name = layerName;
// Add it...
pLayerTable.UpgradeOpen();
layerId = pLayerTable.Add(pNewLTR);
// Let the transaction know about it...
pTr.AddNewlyCreatedDBObject(pNewLTR, true);
}//else

// Commit the transaction...
pTr.Commit();
// Set the current layer...
pDb.Clayer = layerId;
}//try
catch (Autodesk.AutoCAD.Runtime.Exception ex)
{
pEd.WriteMessage("\nError: " + ex.Message);
}
}//using transaction
}//command test

Cheers,
Glenn.

"Tony Tanzillo" wrote in message
news:4916734@discussion.autodesk.com...
If you unerase and re-use the existing entry, where does
the eDuplicateKey error occur?

I don't like the idea of unerasing and re-using a layer
table record (who knows what can be attached to it,
or where it is referenced), but it may be the only way
to do it.

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2004/2005/2006
http://www.acadxtabs.com

"Glenn Ryan" wrote in message
news:4916612@discussion.autodesk.com...
Hi Tony,

Thanks for the reply. That was my suspicion as well,
and I have already tried unerasing the layer if ObjectId.IsErased is true.

You then get an eDuplicateKey error...go figure...anymore suggestions?

Cheers,
Glenn.


"Tony Tanzillo" wrote in message
news:4916128@discussion.autodesk.com...
The default indexer for SymbolTable is calling
AcDbSymbolTable::getAt() and passing true
as the third argument (true = get erased record).

I'm not sure about AcDbSymbolTable::has(), but
since it is not specified in the docs, it is possible
that it is also returning true if an erased record
exists.

My suggestion would be to check the IsErased
property on any ObjectId returned by the default
indexer, and if it is true, then just unerase it.

My guess about why this may be necessary, is that
it's quite possible that symbol tables cannot have
more than one entry with the same name, even if
all but one of them are erased.

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2004/2005/2006
http://www.acadxtabs.com

"Glenn Ryan" wrote in message
news:4915935@discussion.autodesk.com...
Hello everyone,

I've run into some strange behaviour with regards to transactions and
SymbolTableRecords.
If you follow these steps with the code below, you will get an exception of
either eWasErased or eDuplicateRecord.

Steps:

1. Create a brand new drawing.
2. Run the code below.
3. Erase all entities in the drg.
4. Set the current layer to 0.
5. Purge the drawing.
6. Run the code again.
7. Run the code again.

At step 7 you will receive the exception. I've also tried these steps with
all the Adesk supplied samples and labs that I could find that create layers
(in particular) and they all suffer the same fate...any ideas as to why and
how to overcome it?

The code:
using System ;

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Colors;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime ;

using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;

[assembly: CommandClass(typeof(ClassLibrary.tcgsClass))]

namespace ClassLibrary
{
///
/// Summary description for tcgsClass.
///

public class tcgsClass
{
public tcgsClass()
{
//
// TODO: Add constructor logic here
//
}

// Define Command "LayerTest"
[CommandMethod("LayerTest")]
public void test() // This method can have any name
{
Document pDoc = AcadApp.DocumentManager.MdiActiveDocument;
// Get a pointer to the current doc's dbase...
Database pDb = pDoc.Database;
// While we're at it, get a pointer to the editor...
Editor pEd = pDoc.Editor;
// Our 'test' layer name...
string layerName = "Test";
// Our test layer's objectIdnl

ObjectId layerId = ObjectId.Null;
// Kick off a transaction in the current dbase...
using (Transaction pTr = pDb.TransactionManager.StartTransaction())
{
try
{
// Try and open the layer table for write...
LayerTable pLayerTable = (LayerTable)pTr.GetObject(pDb.LayerTableId,
OpenMode.ForWrite, true);
// Does it contain our layer?
if (pLayerTable.Has(layerName))
layerId = pLayerTable[layerName];
else // Nope, so create it...
{
LayerTableRecord pNewLTR = new LayerTableRecord();
// Set the name...
pNewLTR.Name = layerName;
// Add it...
layerId = pLayerTable.Add(pNewLTR);
// Let the transaction know about it...
pTr.AddNewlyCreatedDBObject(pNewLTR, true);
}//else

// Commit the transaction...
pTr.Commit();
// Set the current layer...
pDb.Clayer = layerId;
}//try
catch (Autodesk.AutoCAD.Runtime.Exception ex)
{
pEd.WriteMessage("\nError: " + ex.Message);
}
}//using transaction
}//command test
}//class
}//namespace
*Glenn Ryan
Message 12 of 18 (483 Views)

Re: Transactions, purge and eWasErased...

08-03-2005 05:54 AM in reply to: *Glenn Ryan
Hmmm...the ActiveX item method would still be using an internal loop to find
the record????
I think I would prefer to do the loop myself in native C# if you know what I
mean.

And yes, this is a potential source of some VERY annoying bugs.
Again, thanks for the input.

Cheers,
Glenn.

"Tony Tanzillo" wrote in message
news:4918048@discussion.autodesk.com...
WRT the workaround (iterating over the entire layer
table to find the desired entry), I spoke too soon.

The easy solution is to use ActiveX to get the
AcadLayer object, and then use FromAcadObject
to get the ObjectId.

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2004/2005/2006
http://www.acadxtabs.com

"Glenn Ryan" wrote in message
news:4918031@discussion.autodesk.com...
Tony,

I had already come to the same conclusion and had adjusted my code
acccordingly - thanks for the confirmation.
Thinking out loud, I know the *preferred* way in .net is to have a default
indexer [], but it would be nice to have AcDbSymbolTable::getAt
exposed directly as well, because, as you mentioned, it effects ALL derived
classes as well.

Cheers,
Glenn.

"Tony Tanzillo" wrote in message
news:4917010@discussion.autodesk.com...
The fact that you're getting an eDuplicateRecord error
serves to confirm that the problem is what I said it
was initially, which is that the default indexer for the
SymbolTable managed wrapper class, is incorrectly (IMO)
calling AcDbSymbolTable::getAt() with the third argument
set to true. That will cause it to return the first matching
entry, even if it is erased.

Hence, that effectively makes the default indexer for the
SymbolTable and all derived classes, useless (unless you
want it to return deleted symbol table records, which is
generally not the case).

The only way around it is to iterate over the entire layer
table, to locate the entry with the specified name.

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2004/2005/2006
http://www.acadxtabs.com

"Glenn Ryan" wrote in message
news:4916851@discussion.autodesk.com...
Tony,

If you follow these steps, with the revised code below, you will get the
eDuplicateRecord error:

1. Start blank new drawing.
2. Run code.
3. Set layer 0 current.
4. Purge
5. Run code.
6. Run code.

Revised code (the only thing that has changed is the TRUE branch of the main
IF statement):

[CommandMethod("LayerTest")]
public void test() // This method can have any name
{
Document pDoc = AcadApp.DocumentManager.MdiActiveDocument;
// Get a pointer to the current doc's dbase...
Database pDb = pDoc.Database;
// While we're at it, get a pointer to the editor...
Editor pEd = pDoc.Editor;
// Our 'test' layer name...
string layerName = "Test";
// Our test layer's objectIdnl

ObjectId layerId = ObjectId.Null;
// Kick off a transaction in the current dbase...
using (Transaction pTr = pDb.TransactionManager.StartTransaction())
{
try
{
// Try and open the layer table for write...
LayerTable pLayerTable = (LayerTable)pTr.GetObject(pDb.LayerTableId,
OpenMode.ForRead);
// Does it contain our layer?
if (pLayerTable.Has(layerName))
{
layerId = pLayerTable[layerName];
if (layerId.IsErased)
{
LayerTableRecord pExLtr = (LayerTableRecord)pTr.GetObject(layerId,
OpenMode.ForWrite, true);
pExLtr.Erase(false);
}

}
else // Nope, so create it...
{
LayerTableRecord pNewLTR = new LayerTableRecord();
// Set the name...
pNewLTR.Name = layerName;
// Add it...
pLayerTable.UpgradeOpen();
layerId = pLayerTable.Add(pNewLTR);
// Let the transaction know about it...
pTr.AddNewlyCreatedDBObject(pNewLTR, true);
}//else

// Commit the transaction...
pTr.Commit();
// Set the current layer...
pDb.Clayer = layerId;
}//try
catch (Autodesk.AutoCAD.Runtime.Exception ex)
{
pEd.WriteMessage("\nError: " + ex.Message);
}
}//using transaction
}//command test

Cheers,
Glenn.

"Tony Tanzillo" wrote in message
news:4916734@discussion.autodesk.com...
If you unerase and re-use the existing entry, where does
the eDuplicateKey error occur?

I don't like the idea of unerasing and re-using a layer
table record (who knows what can be attached to it,
or where it is referenced), but it may be the only way
to do it.

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2004/2005/2006
http://www.acadxtabs.com

"Glenn Ryan" wrote in message
news:4916612@discussion.autodesk.com...
Hi Tony,

Thanks for the reply. That was my suspicion as well,
and I have already tried unerasing the layer if ObjectId.IsErased is true.

You then get an eDuplicateKey error...go figure...anymore suggestions?

Cheers,
Glenn.


"Tony Tanzillo" wrote in message
news:4916128@discussion.autodesk.com...
The default indexer for SymbolTable is calling
AcDbSymbolTable::getAt() and passing true
as the third argument (true = get erased record).

I'm not sure about AcDbSymbolTable::has(), but
since it is not specified in the docs, it is possible
that it is also returning true if an erased record
exists.

My suggestion would be to check the IsErased
property on any ObjectId returned by the default
indexer, and if it is true, then just unerase it.

My guess about why this may be necessary, is that
it's quite possible that symbol tables cannot have
more than one entry with the same name, even if
all but one of them are erased.

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2004/2005/2006
http://www.acadxtabs.com

"Glenn Ryan" wrote in message
news:4915935@discussion.autodesk.com...
Hello everyone,

I've run into some strange behaviour with regards to transactions and
SymbolTableRecords.
If you follow these steps with the code below, you will get an exception of
either eWasErased or eDuplicateRecord.

Steps:

1. Create a brand new drawing.
2. Run the code below.
3. Erase all entities in the drg.
4. Set the current layer to 0.
5. Purge the drawing.
6. Run the code again.
7. Run the code again.

At step 7 you will receive the exception. I've also tried these steps with
all the Adesk supplied samples and labs that I could find that create layers
(in particular) and they all suffer the same fate...any ideas as to why and
how to overcome it?

The code:
using System ;

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Colors;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime ;

using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;

[assembly: CommandClass(typeof(ClassLibrary.tcgsClass))]

namespace ClassLibrary
{
///
/// Summary description for tcgsClass.
///

public class tcgsClass
{
public tcgsClass()
{
//
// TODO: Add constructor logic here
//
}

// Define Command "LayerTest"
[CommandMethod("LayerTest")]
public void test() // This method can have any name
{
Document pDoc = AcadApp.DocumentManager.MdiActiveDocument;
// Get a pointer to the current doc's dbase...
Database pDb = pDoc.Database;
// While we're at it, get a pointer to the editor...
Editor pEd = pDoc.Editor;
// Our 'test' layer name...
string layerName = "Test";
// Our test layer's objectIdnl

ObjectId layerId = ObjectId.Null;
// Kick off a transaction in the current dbase...
using (Transaction pTr = pDb.TransactionManager.StartTransaction())
{
try
{
// Try and open the layer table for write...
LayerTable pLayerTable = (LayerTable)pTr.GetObject(pDb.LayerTableId,
OpenMode.ForWrite, true);
// Does it contain our layer?
if (pLayerTable.Has(layerName))
layerId = pLayerTable[layerName];
else // Nope, so create it...
{
LayerTableRecord pNewLTR = new LayerTableRecord();
// Set the name...
pNewLTR.Name = layerName;
// Add it...
layerId = pLayerTable.Add(pNewLTR);
// Let the transaction know about it...
pTr.AddNewlyCreatedDBObject(pNewLTR, true);
}//else

// Commit the transaction...
pTr.Commit();
// Set the current layer...
pDb.Clayer = layerId;
}//try
catch (Autodesk.AutoCAD.Runtime.Exception ex)
{
pEd.WriteMessage("\nError: " + ex.Message);
}
}//using transaction
}//command test
}//class
}//namespace
*Tony Tanzillo
Message 13 of 18 (483 Views)

Re: Transactions, purge and eWasErased...

08-03-2005 06:22 AM in reply to: *Glenn Ryan
"Glenn Ryan" wrote

>> the ActiveX item method would still be using an
>> internal loop to find the record????

No, it does exactly what the SymbolTable's default
indexer does internally (calls AcDbSymbolTable::getAt),
but the ActiveX implementation is native code, which
means the lookup is comparable to pure ObjectARX.

>> I think I would prefer to do the loop myself in
>> native C# if you know what I mean.

If performance is an issue, ActiveX would probably
be much faster than managed code. As a rule of
thumb, managed code is really slow.

Making matters worse, iterating each entry in the
symbol table in managed code requires a managed
wrapper to be created for each record, and you need
it to look at the name of the record anway. That's a
lot more work than the native getAt() has to do.

Of course, you don't have to do either if the Id
returned by the SymbolTable's default indexer is
not erased, so you can check that first before
taking any detours.

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2004/2005/2006
http://www.acadxtabs.com
*Expert Elite*
Sinc
Posts: 6,207
Registered: ‎11-18-2006
Message 14 of 18 (483 Views)

Re: Transactions, purge and eWasErased...

11-28-2007 05:45 PM in reply to: *Glenn Ryan
Just ran into this issue.

Evidently, this problem still exists in the 2008 API.
Sinc
*Tony Tanzillo
Message 15 of 18 (483 Views)

Re: Transactions, purge and eWasErased...

11-29-2007 01:04 AM in reply to: *Glenn Ryan
What problem is that?

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2008
Supporting AutoCAD 2000 through 2008
http://www.acadxtabs.com

wrote in message news:5787849@discussion.autodesk.com...
Just ran into this issue.

Evidently, this problem still exists in the 2008 API.
*Expert Elite*
Sinc
Posts: 6,207
Registered: ‎11-18-2006
Message 16 of 18 (483 Views)

Re: Transactions, purge and eWasErased...

11-29-2007 08:13 AM in reply to: *Glenn Ryan
Default indexer for Symbol Tables may return an erased entity.
Sinc
Contributor
GlennR
Posts: 12
Registered: ‎11-22-2006
Message 17 of 18 (483 Views)

Re: Transactions, purge and eWasErased...

11-30-2007 04:40 AM in reply to: *Glenn Ryan
The default indexer in any .net program can be built to take more than one argument so I've learned. So, maybe, Autodesk should just add an overload for default indexing on symboltables that takes 2 args - the string and a bool for returning erased records and pass that to the appropriate getAt() call. This owuldn't break any previous version as far as I'm aware and could possibly neatly solve the issue...just thinking out loud.

Cheers,
Glenn.
*Tony Tanzillo
Message 18 of 18 (483 Views)

Re: Transactions, purge and eWasErased...

11-30-2007 05:38 AM in reply to: *Glenn Ryan
The fact is that there were any number of ways they could
have addressed this. The fact that they can come here and
see how much posted code is affected by the blind use of
Has(), with the incorrect assumption that a result of 'true'
means that there is a non-erased entry with the specified
name, means they also fully understand the implications of
what they've done.

Yet, they have left this broken.

While I do not concur, it is easy to understand why some
might regard this as deliberate sabotage, with the motive
being to serve the strategic objective of eroding customer
faith and confidence in all custom third-party applications.

And of course, that leads us back to the one simple truth,
which is that Autodesk is not merely at odds with its own
customers, they are literally at war with them.

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2008
Supporting AutoCAD 2000 through 2008
http://www.acadxtabs.com

wrote in message news:5789120@discussion.autodesk.com...
The default indexer in any .net program can be built to take more than one argument so I've learned. So, maybe, Autodesk should just add an overload for default indexing on symboltables that takes 2 args - the string and a bool for returning erased records and pass that to the appropriate getAt() call. This owuldn't break any previous version as far as I'm aware and could possibly neatly solve the issue...just thinking out loud.

Cheers,
Glenn.
Post to the Community

Have questions about Autodesk products? Ask the community.

New Post
Announcements
Do you have 60 seconds to spare? The Autodesk Community Team is revamping our site ranking system and we want your feedback! Please click here to launch the 5 question survey. As always your input is greatly appreciated.