BlockTable/BlockTableRecord (Please correct me if I've got any of this wrong):
As I understand it, the BlockTable is a dictionary of the graphical entities in the database. For each record, the key is an ObjectId, and the value is some object that is essentially an array of entities (What is the root object type? DBObject?Entity?)
It's better to think of AcDbSymbolTable's as a collection and not worry about the plumbing under the hood except what is shown through public API's. The records stored in AcDbSymbolTable's are keyed by a string value associated with an AcDbObjectId object. The AcDbDatabase maintains an association of AcDbObjectId's to the AcDbObject's that own the Id's. So given an AcDbObjectId the AcDbObject can be retrieved, and if you already have a database resident AcDbObject then calling ::objectId() on the object gives you the AcDbObjectId.
There are multiple ways to get an AcDbObjectId or AcDbObject, in the case of AcDbSymbolTable's the AcDbSymbolTableIterator::getRecord and getRecordId can be used.
What is the base type for any given object? That's best figured out by looking the the ARX documentation. I'm biased towards the ARX docs (2008 version) rather than the Managed ARX docs. I feel that the 2008 (maybe 2009) ARX docs are ***way better*** than the 2010+ versions. The ARX docs (2008) information is more complete and better organized than the managed ARX version, YMMV.
How do you know what base types a container class can hold? Again, look at the ARX docs. For objects derived from AcDbSymbolTable, they hold types derived from AcDbSymbolTableRecord. AcDbSymbolTableRecord types can hold...depends on the table record type. Some like AcDbLinetypeTableRecord and AcDbLayerTableRecord are not containers for other objects, others like AcDbBlockTableRecord are containers and hold AcDbEntity derived types.
A BlockTableRecord is conceptually equivalent to a block definition. A "space" such as modelspace is a type of BTR.
Sounds about right.
Transaction Manager Questions:
1. Can someone explain what is happening inside .AddNewlyCreatedDBObject? When I add an entity to a BTR, the argument is that new object; then I pass that same object to the transaction manager. For some reason that doesn't seem intuitive.
At the ARX level there are 2 choices after adding an object or entity to the database (DBR = database resident). 1) close the object 2) hand the object off to the transaction manager.
addNewlyCreatedDBRObject maintains a collection of AcDbObject(s) to be committed or "uncreated" depending endTransaction or abortTransaction being called. If the manager commits then each object is simply closed. When aborted is called, each object is uncreated (which I presume the object is physically removed from the DB, rather than the objects erase bit set and closed, never looked into it)
2. What is the purpose of the boolean in .AddNewlyCreatedObject? I did a search on code that's been posted on this board, and I don't see it ever being passed as false.
Flag to add or remove an object (defaults to true)
From the ARX docs
virtual Acad::ErrorStatus
addNewlyCreatedDBRObject(
AcDbObject* obj,
bool add = true) = 0;
obj Input pointer to the object to be added or removed
add Input Boolean indicating whether to add or remove the object
If add == Adesk::kTrue, the object pointed to by pObject is added to the top transaction. If add == Adesk::kFalse, then the object is removed from whatever transaction it's within.
pObject must point to an object that is newly created (that is, it has never been closed) and is already database resident (that is, it's been added to an AcDbDatabase so it has an objectId).
Returns Acad::eOk if successful. If pObject points to an object that is not newly created, then Acad::eNotNewlyCreated is returned.