Transaktionen in AutoCAD .NET richtig einsetzen

CAD-Modell eines Bauteils auf dem Bildschirm mit Leistungskurve

CAD

Ihr Befehl läuft ohne Fehlermeldung durch – und in der Zeichnung hat sich nichts geändert. Oder schlimmer: Nach einem Fehler ist die Hälfte der Bauteile verschoben, der Rest steht noch an der alten Stelle. Beides sind Fehler im Umgang mit Transaktionen, und beide lassen sich vermeiden.

Die Transaktion als Frühstückstisch

Ein Objekt aus der Zeichnung zu öffnen, ist wie ein Schraubglas aufzuschrauben. Früher hat man jedes Glas einzeln auf- und wieder zugeschraubt, mit Open und Close. Die Transaktion ist der Frühstückstisch dazu: Alles, was Sie über sie öffnen, bleibt offen, bis die Transaktion endet. Dann werden alle Gläser auf einmal geschlossen. Mit Commit bleiben die Änderungen erhalten, ohne Commit kommt alles so zurück, wie es vorher war.

Der Ablauf ist immer gleich:

  1. db.TransactionManager.StartTransaction() beginnt die Transaktion.
  2. tr.GetObject(id, OpenMode.ForRead) oder OpenMode.ForWrite öffnet ein Objekt.
  3. Neue Objekte meldet tr.AddNewlyCreatedDBObject(objekt, true) an, nachdem sie in die Datenbank gehängt wurden.
  4. tr.Commit() übernimmt alle Änderungen.
  5. Dispose beendet die Transaktion. Fehlt das Commit, wird alles zurückgenommen.
[CommandMethod("MeinKreis")]
public void ZeichneKreis()
{
    var db = Application.DocumentManager.MdiActiveDocument.Database;
    using (var tr = db.TransactionManager.StartTransaction())
    {
        var modellbereich = (BlockTableRecord)tr.GetObject(
            SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForWrite);
        var kreis = new Circle(new Point3d(0, 0, 0), Vector3d.ZAxis, 10.0);
        modellbereich.AppendEntity(kreis);
        tr.AddNewlyCreatedDBObject(kreis, true);
        // Ohne Commit nimmt Dispose am Ende des using-Blocks alles zurück
        tr.Commit();
    }
}

Der using-Block sorgt dafür, dass Dispose auch dann aufgerufen wird, wenn unterwegs eine Ausnahme fliegt. Ein vergessenes Commit ist deshalb kein Absturz, sondern ein Befehl, der scheinbar nichts tut – ein Klassiker in unseren Schulungen.

Wo es in der Praxis schiefgeht

Commit in einer inneren Transaktion gilt nur unter Vorbehalt

Transaktionen lassen sich verschachteln. Die äußere nimmt die Änderungen der inneren auf. Bricht die äußere ab, ist auch weg, was die innere schon bestätigt hatte. Wir haben das Muster in echtem Code gefunden: Eine Hilfsmethode legt in einer eigenen Transaktion einen Layer an und bestätigt sauber. Der Aufrufer bestätigt seine äußere Transaktion aber nie, weil er „ja nur gelesen“ hat. Der Layer verschwindet am Ende wieder, und niemand weiß, warum. Beenden Sie verschachtelte Transaktionen außerdem immer von innen nach außen. Wer die äußere zuerst beendet, riskiert einen Absturz ohne jede Meldung. using-Blöcke erledigen die Reihenfolge von selbst.

Commit im Dispose einer eigenen Klasse

Manche Klassen halten die Transaktion als Feld und rufen in ihrem Dispose erst Commit und dann Dispose auf. Das wirkt aufgeräumt, ist aber gefährlich: Dispose läuft auch, wenn der using-Block wegen einer Ausnahme verlassen wird. Dann wird halbe Arbeit gespeichert. Bei einem Kreis ist das ärgerlich, bei hundert Bauteilen eine Katastrophe. Richtig ist eine Klasse, die ausdrücklich bestätigt:

public sealed class Bearbeitung : IDisposable
{
    private readonly Transaction _tr;

    public Bearbeitung(Database db)
    {
        _tr = db.TransactionManager.StartTransaction();
    }

    public void Verschiebe(ObjectId elementId, Vector3d versatz)
    {
        var element = (Entity)_tr.GetObject(elementId, OpenMode.ForWrite);
        element.TransformBy(Matrix3d.Displacement(versatz));
    }

    // Bestätigt wird ausdrücklich – nur wenn alles geklappt hat
    public void Bestätige()
    {
        _tr.Commit();
    }

    // Dispose räumt nur auf und bestätigt nichts
    public void Dispose()
    {
        _tr.Dispose();
    }
}

Der Befehl erzeugt die Klasse in einem using-Block, verschiebt alle Elemente und ruft erst ganz am Ende Bestätige() auf. Fliegt vorher eine Ausnahme, bleibt die Zeichnung unverändert.

Die Transaktion, die niemand beendet

Wird Dispose von Hand am Ende aufgerufen und fliegt vorher eine Ausnahme, bleibt die Transaktion offen. AutoCAD räumt sie am Ende des Befehls nicht weg. Sie bleibt über Befehle hinweg aktiv und liegt jedem folgenden Befehl als TopTransaction vor den Füßen. Eine Transaktion gehört deshalb nie in ein statisches Feld oder in ein Objekt, das länger lebt als der Befehl.

Die schnelle OpenCloseTransaction

StartOpenCloseTransaction sieht aus wie eine Transaktion, öffnet intern aber mit Open und Close. Sie ist schneller, hat aber Eigenheiten: TopTransaction kennt sie nicht, und Abort nimmt neu angelegte Objekte nicht zurück. Sie bleiben als Waisen in der Datenbank. Nehmen Sie sie dort, wo nur gelesen oder geändert wird.

Was Transaktionen kosten

Gemessen haben wir in der AutoCAD-Konsole 2027 mit einem Gelände aus 10.000 Rasterzellen, also 30.000 Linien. Die Zahlen gelten nur für unseren Rechner, die Verhältnisse sind aber aufschlussreich: 10.000 Transaktionen statt einer kosteten nur rund 15 Prozent mehr. Die OpenCloseTransaction war etwa doppelt so schnell. Die eigentliche Bremse ist der Bildschirm: UpdateScreen nach jeder Zelle kostete fast das Dreifache, FlushGraphics nach jeder Zelle das Zwanzigfache. Wer Fortschritt zeigen will, frischt also nicht nach jedem Element auf, sondern alle paar hundert.

Typische Fehler

  • Vergessenes Commit: Der Befehl läuft durch und tut scheinbar nichts.
  • Ein Commit in einer inneren Transaktion gilt als endgültig – bis die äußere abbricht.
  • Commit im Dispose einer eigenen Klasse speichert nach einem Fehler halbe Arbeit.
  • Eine nicht beendete Transaktion überlebt den Befehl und stört alle folgenden.
  • GetObject liefert jedes Mal eine neue .NET-Hülle. Vergleichen Sie Objekte über ihre ObjectId.
  • DowngradeOpen wirkt in einer Transaktion nicht. Öffnen Sie gleich richtig.
  • ObjectId.GetObject ohne laufende Transaktion brachte AutoCAD 2027 in unserem Versuch zum Absturz.

So helfen wir

  • Schulung: Transaktionen, Öffnen und Schließen und sauberes Entsorgen sind Kern der Schulung „AutoCAD .NET API mit C#“. Für BricsCAD gibt es die Schulung „BricsCAD .NET API mit C#“.
  • Code-Check Transaktionen: Wir prüfen Ihr Add-in auf vergessene Commits, verschachtelte Transaktionen und Bremsen beim Zeichnen.
  • Projekt: Ihr Add-in ist langsam oder hinterlässt halbe Änderungen? Vereinbaren Sie ein Erstgespräch.
  • Das Buch: Alle Versuche und Messungen stehen ausführlich in Ebi F. Eilbers Fachbuch „AutoCAD .NET API“, das voraussichtlich 2027 erscheint.

Quelle: Ebi F. Eilber, AutoCAD .NET API (Fachbuch, erscheint voraussichtlich 2027)

KONTAKT

Sprache auswählen

ErstgesprächvereinbarenErstgesprächvereinbaren