Miklix

Mithilfe des SysExtension-Frameworks ermitteln, welche Unterklasse in Dynamics AX 2012 instanziiert werden soll

Veröffentlicht: 16. Februar 2025 um 00:25:37 UTC

In diesem Artikel wird beschrieben, wie Sie das wenig bekannte SysExtension-Framework in Dynamics AX 2012 und Dynamics 365 for Operations verwenden, um Unterklassen basierend auf Attributdekorationen zu instanziieren, was ein leicht erweiterbares Design einer Verarbeitungsklassenhierarchie ermöglicht.


Diese Seite wurde maschinell aus dem Englischen übersetzt, um sie so vielen Menschen wie möglich zugänglich zu machen. Leider ist die maschinelle Übersetzung noch keine ausgereifte Technologie, so dass Fehler auftreten können. Wenn Sie es vorziehen, können Sie sich die englische Originalversion hier ansehen:

Using the SysExtension Framework to Find Out Which Subclass to Instantiate in Dynamics AX 2012

Die Informationen in diesem Beitrag basieren auf Dynamics AX 2012 R3. Sie können für andere Versionen gültig sein, müssen es aber nicht. (Update: Ich kann bestätigen, dass die Informationen in diesem Artikel auch für Dynamics 365 for Operations gültig sind.)

Beim Implementieren von Verarbeitungsklassen in Dynamics AX stehen Sie häufig vor der Aufgabe, eine Klassenhierarchie zu erstellen, in der jede Unterklasse einem Enumerationswert entspricht oder eine andere Datenkopplung aufweist. Ein klassisches Design besteht darin, dann eine Konstruktmethode in der Superklasse zu haben, die einen Schalter hat, der bestimmt, welche Klasse basierend auf der Eingabe instanziiert werden soll.

Dies funktioniert im Prinzip gut, aber wenn Sie viele verschiedene mögliche Eingaben haben (viele Elemente in einer Aufzählung oder vielleicht ist die Eingabe eine Kombination aus mehreren verschiedenen Werten), kann die Wartung mühsam und fehleranfällig werden und das Design hat immer den Nachteil, dass Sie die besagte Konstruktionsmethode ändern müssen, wenn Sie jemals eine neue Unterklasse hinzufügen oder Änderungen daran vornehmen, welche Unterklasse basierend auf welcher Eingabe verwendet werden soll.

Glücklicherweise gibt es hierfür eine viel elegantere, aber leider auch viel weniger bekannte Möglichkeit, nämlich die Verwendung des SysExtension-Frameworks.

Dieses Framework nutzt Attribute, mit denen Sie Ihre Unterklassen dekorieren können, damit das System erkennen kann, welche Unterklasse für welche Verarbeitung verwendet werden soll. Sie benötigen zwar immer noch eine Konstruktionsmethode, aber wenn Sie diese richtig ausführen, müssen Sie sie beim Hinzufügen neuer Unterklassen nie ändern.

Betrachten wir ein fiktives Beispiel und nehmen wir an, dass Sie eine Hierarchie implementieren, die eine Art Verarbeitung auf Grundlage der Tabelle InventTrans durchführt. Welche Verarbeitung durchgeführt wird, hängt von StatusReceipt und StatusIssue der Datensätze ab, sowie davon, ob die Datensätze mit SalesLine, PurchLine oder keinem von beiden verknüpft sind. Schon jetzt sehen Sie sich viele verschiedene Kombinationen an.

Nehmen wir an, Sie wissen, dass Sie derzeit nur eine Handvoll Kombinationen bewältigen müssen, Sie wissen aber auch, dass mit der Zeit immer mehr Kombinationen von Ihnen verlangt werden.

Lassen Sie es uns relativ einfach halten und sagen, dass Sie im Moment nur Datensätze verarbeiten müssen, die mit SalesLine in Zusammenhang stehen und einen StatusIssue von ReservPhysical oder ReservOrdered haben. Alle anderen Kombinationen können Sie im Moment ignorieren. Da Sie aber wissen, dass Sie sie später verarbeiten müssen, sollten Sie Ihren Code so gestalten, dass er leicht erweiterbar ist.

Ihre Hierarchie könnte zunächst etwa so aussehen:

  • MeinProzessor
    • MyProcessor_Sales
      • MyProcessor_Sales_ReservOrdered
      • MyProcessor_Sales_ReservPhysical

Nun könnten Sie problemlos eine Methode in der Superklasse implementieren, die eine Unterklasse basierend auf einem ModuleInventPurchSales und einem StatusIssue-Enum instanziiert. Sie müssen dann jedoch jedes Mal die Superklasse ändern, wenn Sie eine Unterklasse hinzufügen, und das entspricht nicht wirklich der Idee der Vererbung in der objektorientierten Programmierung. Schließlich müssen Sie RunBaseBatch oder SysOperationServiceBase nicht jedes Mal ändern, wenn Sie einen neuen Batch-Job hinzufügen.

Stattdessen können Sie das SysExtension-Framework verwenden. Dazu müssen Sie eine weitere Klasse hinzufügen, die SysAttribute erweitern muss. Diese Klasse wird als Attribut verwendet, mit dem Sie Ihre Verarbeitungsklassen dekorieren können.

Diese Klasse ähnelt stark der Art und Weise, wie Sie eine Datenvertragsklasse für eine SysOperation-Implementierung erstellen würden, da sie einige Datenmitglieder und Parm-Methoden zum Abrufen und Festlegen dieser Werte enthält.

In unserem Fall könnte die Klassendeklaration ungefähr so aussehen:

class MyProcessorSystemAttribute extends SysAttribute
{
    ModuleInventPurchSales  module;
    StatusIssue             statusIssue;
    StatusReceipt           statusReceipt
}

Sie müssen eine neue()-Methode erstellen, um alle Datenelemente zu instanziieren. Wenn Sie möchten, können Sie einigen oder allen davon Standardwerte zuweisen, aber das habe ich nicht getan.

public void new(ModuleInventPurchSales  _module,
                StatusIssue             _statusIssue,
                StatusReceipt           _statusReceipt)
{
    ;

    super();

    module          = _module;
    statusIssue     = _statusIssue;
    statusReceipt   = _statusReceipt;
}

Und Sie sollten auch eine Parm-Methode für jedes Datenelement implementieren, aber ich habe diese hier weggelassen, da ich sicher bin, dass Sie wissen, wie das geht – andernfalls betrachten wir es als eine Übung ;-)

Jetzt können Sie Ihre Attributklasse verwenden, um jede Ihrer Verarbeitungsklassen zu dekorieren. Die Klassendeklarationen könnten beispielsweise so aussehen:

[MyProcessorSystemAttribute(ModuleInventPurchSales::Sales,
                            StatusIssue::None,
                            StatusReceipt::None)]
class MyProcessor_Sales extends MyProcessor
{
}

[MyProcessorSystemAttribute(ModuleInventPurchSales::Sales,
                            StatusIssue::ReservOrdered,
                            StatusReceipt::None)]
class MyProcessor_Sales_ReservOrdered extends MyProcessor_Sales
{
}

[MyProcessorSystemAttribute(ModuleInventPurchSales::Sales,
                            StatusIssue::ReservPhysical,
                            StatusReceipt::None)]
class MyProcessor_Sales_ReservPhysical extends MyProcessor_Sales
{
}

Sie können Ihre Klassen natürlich beliebig benennen. Wichtig dabei ist, dass Sie Ihre Klassen mit Attributen versehen, die der Art der Verarbeitung entsprechen, die sie durchführen. (Denken Sie jedoch daran, dass es in Dynamics AX Namenskonventionen für Klassenhierarchien gibt und es immer eine gute Idee ist, diese nach Möglichkeit einzuhalten.)

Nachdem Sie Ihre Klassen nun so dekoriert haben, dass sie erkennen, welche Art von Verarbeitung jede von ihnen durchführt, können Sie das SysExtension-Framework nutzen, um nach Bedarf Objekte der Unterklassen zu instanziieren.

In Ihrer Superklasse (MyProcessor) könnten Sie eine Konstruktionsmethode wie diese hinzufügen:

public static MyProcessor construct(ModuleInventPurchSales _module,
StatusIssue _statusIssue,
StatusReceipt _statusReceipt)
{
    MyProcessor                 ret;
    MyProcessorSystemAttribute  attribute;
    ;

    attribute = new MyProcessorSystemAttribute( _module,
                                                _statusIssue,
                                                _statusReceipt);

    ret = SysExtensionAppClassFactory::getClassFromSysAttribute(classStr(MyProcessor), attribute);

    if (!ret)
    {
        //  no class found
        //  here you could throw an error, instantiate a default
        //  processor instead, or just do nothing, up to you
    }

    return ret;
}

Der wirklich interessante Teil – und eigentlich das Objekt (verzeihen Sie das Wortspiel) dieses gesamten Beitrags – ist die Methode getClassFromSysAttribute() in der Klasse SysExtensionAppClassFactory. Diese Methode akzeptiert den Namen der Superklasse einer Hierarchie (und diese Superklasse muss nicht an der Spitze der Hierarchie stehen; es bedeutet einfach, dass nur Klassen, die diese Klasse erweitern, in Frage kommen) und ein Attributobjekt.

Anschließend wird ein Objekt einer Klasse zurückgegeben, das die angegebene Superklasse erweitert und mit einem entsprechenden Attribut dekoriert ist.

Sie können der Konstruktionsmethode natürlich so viele weitere Validierungen oder Logik hinzufügen, wie Sie möchten. Wichtig ist jedoch, dass Sie diese Methode nach der Implementierung nie wieder ändern müssen. Sie können der Hierarchie Unterklassen hinzufügen, und solange Sie darauf achten, sie entsprechend zu dekorieren, wird die Konstruktionsmethode sie finden, auch wenn sie beim Schreiben noch nicht vorhanden waren.

Und wie steht es mit der Leistung? Ich habe ehrlich gesagt nicht versucht, einen Benchmark durchzuführen, aber mein Bauchgefühl sagt mir, dass die Leistung wahrscheinlich schlechter ist als die des klassischen Switch-Statement-Designs. Wenn man jedoch bedenkt, dass die meisten Leistungsprobleme in Dynamics AX durch den Datenbankzugriff verursacht werden, würde ich mir darüber keine allzu großen Sorgen machen.

Wenn Sie etwas implementieren, bei dem Tausende von Objekten schnell erstellt werden müssen, sollten Sie dies natürlich genauer untersuchen, aber in den klassischen Fällen, in denen Sie nur ein einzelnes Objekt instanziieren, um eine langwierige Verarbeitung durchzuführen, bezweifle ich, dass dies eine Rolle spielt. Wenn man meinen Tipp zur Fehlerbehebung (nächster Absatz) berücksichtigt, scheint das SysExtension-Framework auf Caching angewiesen zu sein, sodass ich bezweifle, dass es in einem laufenden System zu erheblichen Leistungseinbußen kommt. Fehlerbehebung: Wenn die Konstruktmethode Ihre Unterklassen nicht findet, obwohl Sie sicher sind, dass sie richtig dekoriert sind, kann es sich um ein Caching-Problem handeln. Versuchen Sie, die Caches auf Client und Server zu leeren. Ein Neustart des AOS sollte eigentlich nicht erforderlich sein, aber es kann der letzte Ausweg sein.

Teilen auf BlueskyAuf Facebook teilenAuf LinkedIn teilenAuf Tumblr teilenTeilen auf XAuf LinkedIn teilenPin auf Pinterest

Mikkel Bang Christensen

Über den Autor

Mikkel Bang Christensen
Mikkel ist der Schöpfer und Eigentümer von miklix.com. Er verfügt über mehr als 20 Jahre Erfahrung als professioneller Computerprogrammierer/Softwareentwickler und ist derzeit in Vollzeit für ein großes europäisches IT-Unternehmen tätig. Wenn er nicht gerade bloggt, verbringt er seine Freizeit mit einer Vielzahl von Interessen, Hobbys und Aktivitäten, was sich bis zu einem gewissen Grad in der Vielfalt der auf dieser Website behandelten Themen widerspiegelt.