Miklix

Použitie rámca SysExtension na zistenie, ktorá podtrieda sa má vytvoriť v Dynamics AX 2012

Publikované: 16. februára 2025 o 0:25:58 UTC
Posledná aktualizácia: 12. januára 2026 o 8:43:15 UTC

Tento článok popisuje, ako použiť málo známy framework SysExtension v systémoch Dynamics AX 2012 a Dynamics 365 for Operations na vytvorenie inštancií podtried na základe dekorácií atribútov, čo umožňuje ľahko rozšíriteľný návrh hierarchie tried spracovania.


Táto stránka bola strojovo preložená z angličtiny, aby bola prístupná čo najväčšiemu počtu ľudí. Žiaľ, strojový preklad ešte nie je dokonalá technológia, takže sa môžu vyskytnúť chyby. Ak chcete, môžete si pozrieť pôvodnú anglickú verziu tu:

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

Informácie v tomto príspevku sú založené na systéme Dynamics AX 2012 R3. Môžu, ale nemusia byť platné pre iné verzie. (Aktualizácia: Môžem potvrdiť, že informácie v tomto článku sú platné aj pre systém Dynamics 365 for Operations)

Pri implementácii tried spracovania v systéme Dynamics AX sa často stretávate s vytváraním hierarchie tried, v ktorej každá podtrieda zodpovedá hodnote typu enum alebo má nejaké iné dátové prepojenie. Klasický návrh spočíva v tom, že v nadtriede je potom metóda konštruktu, ktorá má prepínač, ktorý určuje, ktorá trieda sa má vytvoriť na základe vstupu.

V princípe to funguje dobre, ale ak máte veľa rôznych možných vstupov (veľa prvkov vo výčte alebo je vstup kombináciou niekoľkých rôznych hodnôt), údržba sa môže stať zdĺhavou a náchylnou na chyby a návrh má vždy nevýhodu, že budete musieť upraviť uvedenú metódu konštrukcie, ak niekedy pridáte novú podtriedu alebo vykonáte zmeny v tom, ktorá podtrieda by sa mala použiť na základe ktorého vstupu.

Našťastie existuje oveľa elegantnejší, ale bohužiaľ aj oveľa menej známy spôsob, ako to dosiahnuť, a to použitím frameworku SysExtension.

Tento framework využíva atribúty, ktoré môžete použiť na ozdobenie podtried, aby systém dokázal zistiť, ktorá podtrieda by sa mala použiť na spracovanie čoho. Stále budete potrebovať metódu konštruktu, ale ak sa to urobí správne, nikdy ju nebudete musieť upravovať pri pridávaní nových podtried.

Pozrime sa na imaginárny príklad. Povedzme, že implementujete hierarchiu, ktorá vykonáva nejaký druh spracovania na základe tabuľky InventTrans. To, ktoré spracovanie sa má vykonať, závisí od záznamov StatusReceipt a StatusIssue, ako aj od toho, či záznamy súvisia s SalesLine, PurchLine alebo ani s jedným. Už teraz sa pozeráte na veľa rôznych kombinácií.

Povedzme, že viete, že zatiaľ potrebujete spracovať iba niekoľko kombinácií, ale tiež viete, že časom budete musieť zvládnuť stále viac a viac kombinácií.

Povedzme si, že zatiaľ potrebujete spracovať iba záznamy súvisiace s SalesLine so stavom StatusIssue typu ReservPhysical alebo ReservOrdered. Všetky ostatné kombinácie môžete zatiaľ ignorovať, ale keďže viete, že ich budete musieť spracovať neskôr, budete chcieť navrhnúť svoj kód tak, aby bol ľahko rozšíriteľný.

Vaša hierarchia môže zatiaľ vyzerať nejako takto:

  • MôjProcesorMôjProcesorPredajMôjProcesorPredajná_RezervaObjednanéMôjProcesorPredajná_RezervaFyzické

Teraz by ste mohli ľahko implementovať metódu v nadtriede, ktorá vytvorí inštanciu podtriedy na základe ModuleInventPurchSales a výčtu StatusIssue. Potom však budete musieť upravovať nadtriedu vždy, keď pridáte podtriedu, a to nie je skutočná myšlienka dedenia v objektovo orientovanom programovaní. Koniec koncov, nemusíte upravovať RunBaseBatch alebo SysOperationServiceBase vždy, keď pridáte novú dávkovú úlohu.

Namiesto toho môžete použiť framework SysExtension. To si bude vyžadovať pridanie ďalšej triedy, ktorá musí rozširovať SysAttribute. Táto trieda sa použije ako atribút, ktorým môžete ozdobiť svoje triedy spracovania.

Táto trieda je veľmi podobná tomu, ako by ste vytvorili triedu dátových kontraktov pre implementáciu SysOperation, v tom, že bude mať niektoré dátové členy a metódy parm na získanie a nastavenie týchto hodnôt.

V našom prípade môže ClassDeclaration vyzerať nejako takto:

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

Musíte vytvoriť metódu new() na vytvorenie inštancie všetkých dátových členov. Ak chcete, môžete niektorým alebo všetkým z nich priradiť predvolené hodnoty, ale ja som to neurobil.

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

    super();

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

A mali by ste tiež implementovať metódu parm pre každý dátový člen, ale tie som tu vynechal, pretože som si istý, že viete, ako na to - inak to považujme za cvičenie ;-)

Teraz môžete použiť svoju triedu atribútov na ozdobenie každej z vašich tried spracovania. Deklarácie tried by mohli vyzerať napríklad takto:

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

Svoje triedy môžete samozrejme pomenovať ľubovoľne, dôležité je však, aby ste ich ozdobili atribútmi, ktoré zodpovedajú typu spracovania, ktoré vykonávajú. (Majte však na pamäti, že v systéme Dynamics AX existujú konvencie pomenovania pre hierarchie tried a vždy je dobré ich dodržiavať, ak je to možné).

Teraz, keď ste si upravili triedy tak, aby ste identifikovali, aký druh spracovania každá z nich vykonáva, môžete podľa potreby využiť framework SysExtension na vytvorenie inštancií objektov podtried.

Vo vašej nadtriede (MyProcessor) môžete pridať metódu konštruktu takto:

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

Skutočne zaujímavá časť – a vlastne cieľ (prepáčte slovnú hračku) celého tohto príspevku – je metóda getClassFromSysAttribute() v triede SysExtensionAppClassFactory. Táto metóda prijíma názov nadtriedy hierarchie (a táto nadtrieda nemusí byť na vrchole hierarchie; znamená to jednoducho, že oprávnené budú iba triedy rozširujúce túto triedu) a objekt atribútu.

Potom vráti objekt triedy, ktorá rozširuje zadanú nadtriedu a je ozdobená zodpovedajúcim atribútom.

Samozrejme, do metódy konštruktu môžete pridať toľko ďalších overení alebo logiky, koľko chcete, ale dôležitým poznatkom je, že po implementácii by ste túto metódu už nikdy nemali musieť upravovať. Do hierarchie môžete pridať podtriedy a pokiaľ ich vhodne ozdobíte, metóda konštruktu ich nájde, aj keď v čase jej napísania neexistovali.

Čo výkon? Úprimne som sa to nepokúšal porovnať, ale mám pocit, že to pravdepodobne funguje horšie ako klasický návrh príkazu switch. Avšak vzhľadom na to, že zďaleka najviac problémov s výkonom v Dynamics AX je spôsobených prístupom k databáze, príliš by som sa tým netrápil.

Samozrejme, ak implementujete niečo, čo bude vyžadovať rýchle vytvorenie tisícok objektov, možno budete chcieť ďalej preskúmať, ale v klasických prípadoch, keď vytvoríte iba jeden objekt na vykonanie zdĺhavého spracovania, pochybujem, že to bude mať význam. Tiež vzhľadom na môj tip na riešenie problémov (ďalší odsek) sa zdá, že framework SysExtension sa spolieha na ukladanie do vyrovnávacej pamäte, takže v bežiacom systéme pochybujem, že má výrazný vplyv na výkon.

Riešenie problémov: Ak metóda konštruktu nenájde vaše podtriedy, aj keď ste si istí, že sú správne upravené, môže ísť o problém s vyrovnávacou pamäťou. Skúste vymazať vyrovnávaciu pamäť na klientovi aj serveri. Nemalo by byť potrebné reštartovať AOS, ale môže to byť posledná možnosť.

Ďalšie čítanie

Ak sa vám tento príspevok páčil, možno sa vám budú páčiť aj tieto návrhy:


Zdieľať na BlueskyZdieľať na FacebookuZdieľať na LinkedInZdieľať na TumblrZdieľať na XZdieľať na LinkedInPripnúť na Pintereste

Mikkel Christensen

O autorovi

Mikkel Christensen
Mikkel je tvorcom a majiteľom miklix.com. Má viac ako 20 rokov skúseností ako profesionálny počítačový programátor/vývojár softvéru a v súčasnosti pracuje na plný úväzok pre veľkú európsku IT korporáciu. Keď práve nepíše blog, venuje svoj voľný čas širokej škále záujmov, koníčkov a aktivít, čo sa môže do istej miery odrážať v rôznorodosti tém na tejto webovej lokalite.