Wie können Objekte externer Referenzen geöffnet werden?
- Wie können Objekte externer Referenzen geöffnet werden? (eNotFromThisDocument)
Acad::ErrorStatus es = Acad::eOk;
AcDbObject *pObj = NULL;
actrTransactionManager->startTransaction();
es = actrTransactionManager->getObject(
(AcDbObject*&)pObj,
pXrefDatabase->layerTableId(),
AcDb::kForRead,
false);
actrTransactionManager->endTransaction();
/* es == Acad::eNotFromThisDocument */
}[/code]- In der ARX-Implementierung arbeiten wir den XRefGraph ab und prüfen alle Nodes auf den Status kXrfNotifyResolvedUpdateAvailable. Alle XRefs mit diesem Status werden in ein AcDbObjectIdArray eingefügt und dieses an acedXrefReload übergeben. Wie ist die Vorgehensweise in BRX?
Auszug aus brx_log.txt:
Function: enum AcDb::XrefNotificationStatus __cdecl AcDbXrefGraphNode::xrefNotificationStatus(void) const
Export : ?xrefNotificationStatus@AcDbXrefGraphNode@@QEBA?AW4XrefNotificationStatus@AcDb@@XZ
- Unter ARX wird ein exklusiver Schreibzugriff auf eine XRef erwirkt, indem AcEdXrefFileLock::lockFile mit AcDbDatabase->xrefBlockId() der Xref-Datenbank aufgerufen wird. BRX meldet eFileNotFound
- AcDbDatabase->originalFileName() gibt immer null zurück
Comments
-
Hallo,
kleiner Tip :
actrTransactionManager->startTransaction();
erstellt eine Transaktion in der *aktuellen* Datenbank ... ist dies so gewollt, oder soll die Transaktion in der XRef-Datenbank erfolgen ?
Ansonsten :
ein kleines Beispiel-Projekt (brxSample aus dem BRX SDK kann einfach angepasst werden), und mit Beispiel-Zeichnung + xref-Zeichnung(en) als SupportRequest einstellen ?
Dann können wir uns das im Detail anschauen, und BricsCAD / BRX korrigieren.
viele Grüsse
Torsten0 -
Hallo Torsten,Danke für die schnelle Antwort. Du hast den Kern unseres ersten Problems genau getroffen. In ARX ist der Transaktionsmanager ein globales Manager-Objekt, das für alle Zeichnungen verwendet wird und über das Makro actrTransactionManager angesprochen werden kann. In BRX hat hingegen jede AcDbDatabase ihren eigenen Transaktionsmanager. Da aber jedes AcDbObject und jede AcDbObjectId die Funktion database() mitbringt, müssen die Methodensignaturen in aller Regel nicht angepasst werden. Die Referenz auf den "zuständigen" Transaktionsmanager kann innerhalb der Methode geholt werden.Aus der ARX-Variante:void ARXTest::doSomethingWithObject(AcDbObject *pObj) {actrTransactionManager->startTransaction();...actrTransactionManager->endTransaction();}Wird die BRX-Variante:void BRXTest::doSomethingWithObject(AcDbObject *pObj) {AcDbTransactionManager *pTransactionManager = pObj->database()->transactionManager();pTransactionManager->startTransaction();...pTransactionManager->endTransaction();}void BRXTest::doSomethingWithObjectId(AcDbObjectId objectId) {AcDbTransactionManager *pTransactionManager = objectId->database()->transactionManager();pTransactionManager->startTransaction();...pTransactionManager->endTransaction();}Viele Grüße,Samuel0
-
Hallo, Samuel,
na, da ist immer noch ein Missverständnis :-)
Auch ARX hat einen DB-spezifischen TransactionManager :
AcDbTransactionManager *AcDbDatabase::transactionManager() const;
jenes Macro "actrTransactionManager" als
AcTransactionManager::cast(acrxSysRegistry()->at(AC_TRANSACTION_MANAGER_OBJ))
ist nur eine Indirektion ...
actrTransactionManager->startTransaction()
leitet dann um auf
acdbCurDwg()->transactionMnaager->startTransaction()
d.h. Umlenkung auf den Database-spezifischen TransactionManager der aktuellen Datenbank um - und die Transaktion wird dann effektiv in der Datenbank gestartet.
Insofern besteht zwischen ARX und BRX kein Unterschied :-)
Auch bei uns ist dies alles exakt wie in ARX implementiert ...
Es ist nur ein verbreitetes Missverständnis, dass eine Transaktion global wäre ...
d.h. actrTransactionManager->startTransaction() sich dann "auf alles" beziehen würde (also auf alle Datenbanken) ... stattdessen läuft die Transaktion nur in der "acdbuzrDwg()" Datenbank, sonstige spielen hier keine Rolle und werden durch die Transaktion nicht erfasst ...
Ich hoffe die Konfusionen noch ein wenig angeheizt zu haben ? :-) :-)
viele Grüsse !0 -
Hallo Torsten,Danke für Deine ausführliche Antwort - die Konfusion ist in der Tat weit fortgeschritten ;-)Im Übrigen könnte der folgende Passus aus der ObjectARX2007-Doku zur Verbreitung des Missverständnisses durchaus beitragen:There is a single object of class AcTransactionManager created by the ObjectARX system when AutoCAD first starts up. This AcTransactionManager object is globally available to all ObjectARX applications. The macro actrTransactionManager returns a pointer to the system AcTransactionManager object to allow access to its member functions.Übers Wochenende konnte ich mich der Problematik mit einigen kleinen Test-Programmen nähern und meine immer noch, einen Unterschied festzustellen:In ARX kann ich über die Blocktabelle iterieren und mit einem Transaktionsmanager alle Objekte zum Lesen öffnen.Wenn ich das Gleiche in BRX versuche erhalte ich bei den Blocks der referenzierten Zeichnungen besagten eNotFromThisDocument Returncode.Beiliegend findest Du zwei Zeichnungen MasterBlock.dwg und ReferenzBlock.dwg. Beide Zeichnungen enthalten je eine Blockdefinition (MasterBlock/RefBlock). Die MasterBlock.dwg enthält eine externe Referenz auf ReferenzBlock.dwg.Der Befehl "TransactionManager" gibt mir unter BRX folgenden Output:[code]Testing actrTransactionManagerBlock *Model_Space was successfully opened for read.Block *Paper_Space was successfully opened for read.Block *Paper_Space0 was successfully opened for read.Block MasterBlock was successfully opened for read.Block ReferenzBlock was successfully opened for read.Error eNotFromThisDocument while opening blocktablerecord for read[/code]Unter ARX erhalte ich:[code]Testing actrTransactionManagerBlock *Model_Space was successfully opened for read.Block *Paper_Space was successfully opened for read.Block *Paper_Space0 was successfully opened for read.Block MasterBlock was successfully opened for read.Block ReferenzBlock was successfully opened for read.Block ReferenzBlock|RefBlock was successfully opened for read.[/code]Ich hoffe Du kannst mit dem beiliegenden Material etwas anfangen, sonst melde Dich gerne wieder.Danke für Deine Unterstützung!Viele Grüße,Samuel0
-
Hallo, Samuel,
Danke für Deine Tests & Hinweise &Code sample ...
ich werde mal unseren BRX Testcode prüfen, ob wir einen dedizierten Test für Dein Szenario haben, und ggf. BRX korrigieren.
So auf die Schnelle scheint es möglich, dass in ARX der "globale" TAManager (welcher ja nur die Funktionen weiterleitet) ggf. erkennt, dass in der Database des ObjectId's keine Transaktion läuft, and daher auf das normale acdbOpenAcDbObject() umlenkt ...
In diesem Falle hätte die Transaktion in Ziel-DB gar keinen Effekt auf die Objekte von der XRef-DB ... bliebe also wirkungslos (aber auch nicht schädlich).
Ich werde das auf alle Fälle prüfen ...
und hier aktualisieren
viele Grüsse !0 -
Hallo, Samuel,
da war tatsächlich eine Macke in BRX ... die AcDbDatabase eines XRefs wurde wie eine externe DB behandelt, daher der Fehlerstatus.
Ist nun korrigiert, und in unser automatisches Testsystem integriert, arbeitet nun wie erwartet ...
also herzlichen Dank !!
Tip :
solange Objekte nur mit kForRead geöffnet werden, ist eine Transaktion nicht notwendig, hat keinerlei Vorteil ...
erst wenn Objekte modifiziert werden (kForWrite etc.), dann machen Transaktionen Sinn.
viele Grüsse & nochmals Dank !0 -
@ Torsten:
Will this changed behavior also have an impact on the Lisp API?0 -
Dear Roy,
no, there is no impact to Lisp here ... it only affects BRX application;
background : ARX has 2 methods to open an object, one normal, one particulary under transaction condition;
Teigha system only has 1 method, which automatically adds an opened object to a running transaction (if any is present).
For the transactions, enabled by VLE transaction function, all opening of objects happens by Teigha generic function.
many greetings & a nice day !0 -
@ Tortsen: Thank you.0
-
Hallo Torsten,vielen Dank für Deine Rückmeldung!Kannst Du mir schon einen Ausblick geben, ab wann eine Version von BricsCAD bereitsteht, mit der ich weiter testen kann? Falls verfügbar gerne auch ein "Nightly build".Danke & viele Grüße,Samuel0
-
Hallo, Samuel,
mal einfach mit der neuen V16.2.08 testen ...
abgesehen davon - solange Objekte nur zum Lesen geöffnet werden, braucht man keine Transaktion :-)
Insofern reicht dann ja acdbOpenObject() ...
Nightly builds haben wir leider nicht ...
Alternativ : wenn getObject() einen Fehler liefert, dann zweiten Versuch mit acdbOpenObject() ?
Aber eben nur sinnvoll mit kForRead, mit kForWrite bleibt das Objekt ja ausserhalb der Transaktion.
viele Grüsse !0 -
Hallo Torsten,auch in V16.2.08 bekomme ich den Fehlerstatus eNotFromThisDocument beim Zugriff auf Blockdatensätze externer Referenzen.Ich habe ein bestehendes Projekt von deutlich über zehntausend Zeilen, das gänzlich auf Transaktionen setzt. Diese Entscheidung wurde bei der Entwicklung damals gefällt, da damit der Aufruf der close-Methode auf den Objekten entfallen und der Code deutlich kompakter und besser gegliedert werden konnte. Je Entität gibt es eine Getter-Methode, die öffnen, casten und Fehlerbehandlung kapselt. Der Umbau auf acdbOpenObject wäre ziemlich zeitintensiv. Zudem wird bei einigen Objekten upgradeOpen genutzt, um zu einem späteren Zeitpunkt Schreibrechte zu erwerben.Wenn ich Deine Ausführungen richtig verstehe, landen in BricsCAD alle Objekt-Zugriffe in derselben Teigha-Methode. Ist ein Aufruf von close bei laufender Transaktion in BRX erforderlich? Wie verhält es sich bei schreibendem Zugriff auf externe Referenzen?Danke & beste Grüße,Samuel0
-
Hi, Samuel,
die Korrekturen sind noch nicht in der V16.2.08 drin, hat sich etwas überlappt ... leider.
Zwar werden schreibende Zugriffe auch letztlich in Teigha abgearbeitet - aber BRX setzt es sich ja zur Aufgabe die ARX Funktionalität nachzubilden.
Das Verhalten mit close(), addNewlyCreatedObject() usw. ist alles wie in ARX, das klappt alles sehr gut (abgesehen von diesem Bug).
Es sollte aber helfen, bei den Öffnen Zugriffen zu prüfen, ob in der ObjectId::database() eine Transaktion arbeitet - wenn nicht, dann acdbOpenAcDbObject(), anderenfalls getObject() ... ersteres aber das kann natürlich fehlschlagen, wenn mehrfaches Öffnen mit kForWrite erforderlich ist.
Ich hoofe mal, dass das nächste BricsCAD Update dann diese Korrektur hier enthält.
viele Grüsse !0