Miklix

Het SysExtension Framework gebruiken om erachter te komen welke subklasse u moet instantiëren in Dynamics AX 2012

Gepubliceerd: 16 februari 2025 om 00:25:53 UTC

In dit artikel wordt beschreven hoe u het weinig bekende SysExtension-framework in Dynamics AX 2012 en Dynamics 365 for Operations kunt gebruiken om subklassen te instantiëren op basis van kenmerkdecoraties, waardoor een eenvoudig uitbreidbaar ontwerp van een verwerkingsklassenhiërarchie mogelijk wordt.


Deze pagina is machinaal uit het Engels vertaald om hem voor zoveel mogelijk mensen toegankelijk te maken. Helaas is machinevertaling nog geen geperfectioneerde technologie, dus er kunnen fouten optreden. Als je dat liever hebt, kun je hier de originele Engelse versie bekijken:

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

De informatie in dit bericht is gebaseerd op Dynamics AX 2012 R3. Het kan wel of niet geldig zijn voor andere versies. (Update: Ik kan bevestigen dat de informatie in dit artikel ook geldig is voor Dynamics 365 for Operations)

Bij het implementeren van verwerkingsklassen in Dynamics AX, wordt u vaak geconfronteerd met het maken van een klassenhiërarchie waarin elke subklasse overeenkomt met een enum-waarde of een andere gegevenskoppeling heeft. Een klassiek ontwerp is om vervolgens een construct-methode in de superklasse te hebben, die een switch heeft die bepaalt welke klasse moet worden geïnstantieerd op basis van de invoer.

In principe werkt dit prima, maar als u veel verschillende mogelijke invoerwaarden hebt (veel elementen in een enum of de invoer is een combinatie van verschillende waarden), kan het lastig en foutgevoelig zijn om te onderhouden. Bovendien heeft het ontwerp altijd het nadeel dat u de constructiemethode moet aanpassen als u ooit een nieuwe subklasse toevoegt of wijzigingen aanbrengt in welke subklasse moet worden gebruikt op basis van welke invoer.

Gelukkig is er een veel elegantere, maar helaas ook veel minder bekende, manier om dit te doen, namelijk door gebruik te maken van het SysExtension-framework.

Dit framework maakt gebruik van attributen die u kunt gebruiken om uw subklassen te decoreren, zodat het systeem kan bepalen welke subklasse moet worden gebruikt om wat te verwerken. U hebt nog steeds een construct-methode nodig, maar als u dit correct doet, hoeft u deze nooit te wijzigen wanneer u nieuwe subklassen toevoegt.

Laten we eens kijken naar een denkbeeldig voorbeeld en zeggen dat je een hiërarchie gaat implementeren die een soort verwerking uitvoert op basis van de InventTrans-tabel. Welke verwerking je moet uitvoeren, hangt af van de StatusReceipt en StatusIssue van de records, en ook van of de records gerelateerd zijn aan SalesLine, PurchLine of geen van beide. Nu al kijk je naar een heleboel verschillende combinaties.

Stel dat u weet dat u op dit moment slechts een paar combinaties hoeft te verwerken, maar dat u ook weet dat u in de loop van de tijd steeds meer combinaties moet kunnen verwerken.

Laten we het relatief eenvoudig houden en zeggen dat u op dit moment alleen records hoeft te verwerken die gerelateerd zijn aan SalesLine met een StatusIssue van ReservPhysical of ReservOrdered. Alle andere combinaties kunt u op dit moment negeren, maar omdat u weet dat u ze later moet verwerken, wilt u uw code zo ontwerpen dat deze eenvoudig uitbreidbaar is.

Uw hiërarchie kan er nu ongeveer zo uitzien:

  • MijnProcessor
    • MijnProcessor_Verkoop
      • MyProcessor_Sales_ReserveGeorderd
      • MyProcessor_Sales_ReserveFysiek

Nu zou je eenvoudig een methode in de superklasse kunnen implementeren die een subklasse instantieert op basis van een ModuleInventPurchSales en een StatusIssue enum. Maar dan moet je de superklasse elke keer dat je een subklasse toevoegt, aanpassen, en dat is niet echt het idee van overerving in objectgeoriënteerd programmeren. Je hoeft tenslotte niet RunBaseBatch of SysOperationServiceBase aan te passen elke keer dat je een nieuwe batchjob toevoegt.

In plaats daarvan kunt u gebruikmaken van het SysExtension-framework. Hiervoor moet u een andere klasse toevoegen, die SysAttribute moet uitbreiden. Deze klasse wordt gebruikt als het kenmerk waarmee u uw verwerkingsklassen kunt decoreren.

Deze klasse lijkt erg op de manier waarop u een gegevenscontractklasse maakt voor een SysOperation-implementatie. Deze klasse bevat namelijk een aantal gegevensleden en parm-methoden om die waarden op te halen en in te stellen.

In ons geval kan de ClassDeclaration er ongeveer zo uitzien:

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

Je moet een new()-methode maken om alle dataleden te instantiëren. Als je wilt, kun je sommige of alle standaardwaarden geven, maar dat heb ik niet gedaan.

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

    super();

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

Je zou ook een parm-methode voor elk data-element moeten implementeren, maar die heb ik hier weggelaten omdat ik er zeker van ben dat je weet hoe je dat moet doen. Anders beschouwen we het als een oefening ;-)

Nu kunt u uw attribuutklasse gebruiken om elk van uw verwerkingsklassen te decoreren. De klassedeclaraties kunnen er bijvoorbeeld zo uitzien:

[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
{
}

U kunt uw klassen uiteraard elke gewenste naam geven. Het belangrijkste hierbij is dat u uw klassen decoreert met kenmerken die overeenkomen met het soort verwerking dat ze uitvoeren. (Houd er echter rekening mee dat er naamgevingsconventies zijn voor klassenhiërarchieën in Dynamics AX en dat het altijd een goed idee is om deze te volgen, indien mogelijk).

Nu u uw klassen hebt ingericht om aan te geven wat voor soort verwerking elke klasse uitvoert, kunt u het SysExtension-framework gebruiken om indien nodig objecten van de subklassen te instantiëren.

In uw superklasse (MyProcessor) kunt u een constructmethode als deze toevoegen:

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;
}

Het echt interessante deel - en eigenlijk het object (sorry voor de woordspeling) van dit hele bericht - is de getClassFromSysAttribute()-methode in de SysExtensionAppClassFactory-klasse. Wat deze methode doet, is dat het de naam van de superklasse van een hiërarchie accepteert (en deze superklasse hoeft niet bovenaan de hiërarchie te staan; het betekent gewoon dat alleen klassen die deze klasse uitbreiden in aanmerking komen) en een kenmerkobject.

Vervolgens wordt een object van een klasse geretourneerd dat de opgegeven superklasse uitbreidt en is voorzien van een overeenkomstig kenmerk.

U kunt uiteraard zoveel verdere validatie of logica toevoegen aan de construct-methode als u wilt, maar de belangrijkste les hier is dat u deze methode, zodra deze is geïmplementeerd, nooit meer hoeft te wijzigen. U kunt subklassen toevoegen aan de hiërarchie en zolang u ervoor zorgt dat u ze op de juiste manier decoreert, zal de construct-methode ze vinden, ook al bestonden ze niet toen deze werd geschreven.

Hoe zit het met de prestaties? Ik heb eerlijk gezegd niet geprobeerd om het te benchmarken, maar mijn onderbuikgevoel zegt dat dit waarschijnlijk slechter presteert dan het klassieke switch statement-ontwerp. Maar aangezien de meeste prestatieproblemen in Dynamics AX worden veroorzaakt door databasetoegang, zou ik me er niet al te veel zorgen over maken.

Natuurlijk, als u iets implementeert waarvoor duizenden objecten snel moeten worden gemaakt, wilt u het misschien verder onderzoeken, maar in de klassieke gevallen waarin u slechts één object instantieert om een langdurige verwerking uit te voeren, betwijfel ik of het uitmaakt. Ook, gezien mijn tip voor probleemoplossing (volgende alinea), lijkt het erop dat het SysExtension-framework afhankelijk is van caching, dus in een lopend systeem betwijfel ik of het een significante prestatiehit heeft. Probleemoplossing: Als de construct-methode uw subklassen niet vindt, ook al weet u zeker dat ze correct zijn gedecoreerd, kan het een cacheprobleem zijn. Probeer caches op zowel de client als de server te wissen. Het zou niet nodig moeten zijn om de AOS daadwerkelijk opnieuw op te starten, maar het kan een laatste redmiddel zijn.

Delen op BlueskyDelen op FacebookDelen op LinkedInDelen op TumblrDelen op XDelen op LinkedInPin op Pinterest

Mikkel Bang Christensen

Over de auteur

Mikkel Bang Christensen
Mikkel is de bedenker en eigenaar van miklix.com. Hij heeft meer dan 20 jaar ervaring als professioneel computerprogrammeur/softwareontwikkelaar en werkt momenteel fulltime voor een groot Europees IT-bedrijf. Als hij niet blogt, besteedt hij zijn vrije tijd aan een breed scala aan interesses, hobby's en activiteiten, die tot op zekere hoogte weerspiegeld kunnen worden in de verscheidenheid aan onderwerpen op deze website.