.NET

Reply
*Glenn Ryan
Message 1 of 18 (282 Views)

Transactions, purge and eWasErased...

282 Views, 17 Replies
08-01-2005 04:55 AM
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 2 of 18 (282 Views)

Re: Transactions, purge and eWasErased...

08-01-2005 08:32 AM in reply to: *Glenn Ryan
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 3 of 18 (282 Views)

Re: Transactions, purge and eWasErased...

08-01-2005 02:56 PM in reply to: *Glenn Ryan
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 4 of 18 (282 Views)

Re: Transactions, purge and eWasErased...

08-01-2005 08:45 PM in reply to: *Glenn Ryan
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 5 of 18 (282 Views)

Re: Transactions, purge and eWasErased...

08-02-2005 04:17 AM in reply to: *Glenn Ryan
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 6 of 18 (282 Views)

Re: Transactions, purge and eWasErased...

08-02-2005 04:19 AM in reply to: *Glenn Ryan
Tony, I forgot to mention that I don't like the idea of unerasing a table
entry either...too many potential dependencies as you noted...

"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 7 of 18 (282 Views)

Re: Transactions, purge and eWasErased...

08-02-2005 06:29 AM in reply to: *Glenn Ryan
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 8 of 18 (282 Views)

Re: Transactions, purge and eWasErased...

08-03-2005 02:51 AM in reply to: *Glenn Ryan
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 9 of 18 (282 Views)

Re: Transactions, purge and eWasErased...

08-03-2005 03:52 AM in reply to: *Glenn Ryan
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 10 of 18 (282 Views)

Re: Transactions, purge and eWasErased...

08-03-2005 05:00 AM in reply to: *Glenn Ryan
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
Announcements
Are you familiar with the Autodesk Expert Elites? The Expert Elite program is made up of customers that help other customers by sharing knowledge and exemplifying an engaging style of collaboration. To learn more, please visit our Expert Elite website.
Need installation help?

Start with some of our most frequented solutions or visit the Installation and Licensing Forum to get help installing your software.