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
Tento článok popisuje, ako používať málo známy rámec SysExtension v Dynamics AX 2012 a Dynamics 365 for Operations na vytváranie inštancií podtried na základe dekorácií atribútov, čo umožňuje jednoducho rozšíriteľný návrh hierarchie tried spracovania.
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 Dynamics AX 2012 R3. Môže a nemusí platiť pre iné verzie. (Aktualizácia: Môžem potvrdiť, že informácie v tomto článku platia aj pre Dynamics 365 for Operations)
Pri implementácii tried spracovania v Dynamics AX sa často stretávate s vytvorením hierarchie tried, v ktorej každá podtrieda zodpovedá hodnote enum alebo má nejaké iné prepojenie údajov. Klasický dizajn je potom mať metódu konštrukcie v super triede, 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 v enume alebo možno vstup je kombináciou niekoľkých rôznych hodnôt), údržba môže byť únavná a náchylná na chyby a dizajn má vždy tú nevýhodu, že budete musieť upraviť uvedenú metódu konštrukcie, ak niekedy pridáte novú podtriedu alebo vykonáte zmeny, ktorá podtrieda by sa mala použiť na základe toho, ktorý vstup.
Našťastie existuje oveľa elegantnejší, ale bohužiaľ aj oveľa menej známy spôsob, ako to urobiť, a to pomocou rámca SysExtension.
Tento rámec využíva atribúty, ktoré môžete použiť na zdobenie svojich podtried, aby bol systém schopný zistiť, ktorá podtrieda by sa mala použiť na spracovanie čoho. Stále budete potrebovať metódu konštrukcie, ale ak sa vykoná správne, nikdy ju nebudete musieť upravovať pri pridávaní nových podtried.
Pozrime sa na imaginárny príklad a povedzme, že idete implementovať hierarchiu, ktorá vykonáva určitý druh spracovania na základe tabuľky InventTrans. Aké spracovanie sa má vykonať, závisí od StatusReceipt a StatusIssue záznamov, ako aj od toho, či záznamy súvisia s SalesLine, PurchLine alebo nie. Už teraz sa pozeráte na množstvo rôznych kombinácií.
Povedzme teda, že viete, že zatiaľ potrebujete zvládnuť len niekoľko kombinácií, no zároveň viete, že sa vám bude časom žiadať, aby ste zvládli stále viac kombinácií.
Urobme to relatívne jednoducho a povedzme, že zatiaľ stačí spracovávať záznamy súvisiace s SalesLine pomocou StatusIssue ReservPhysical alebo ReservOrdered, všetky ostatné kombinácie môžete zatiaľ ignorovať, ale keďže viete, že ich budete musieť zvládnuť neskôr, budete chcieť navrhnúť svoj kód tak, aby bol ľahko rozšíriteľný.
Vaša hierarchia môže zatiaľ vyzerať takto:
- Môj Procesor
- MyProcessor_Sales
- MyProcessor_Sales_ReservOrdered
- MyProcessor_Sales_ReservPhysical
- MyProcessor_Sales
Teraz môžete jednoducho implementovať metódu v super triede, ktorá vytvorí inštanciu podtriedy na základe ModuleInventPurchSales a StatusIssue enum. Potom však budete musieť upraviť supertriedu zakaždým, keď pridáte podtriedu, a to v skutočnosti nie je myšlienkou dedenia v objektovo orientovanom programovaní. Koniec koncov, nemusíte upravovať RunBaseBatch alebo SysOperationServiceBase zakaždým, keď pridáte novú dávkovú úlohu.
Namiesto toho môžete využiť rámec SysExtension. To bude vyžadovať, aby ste pridali ďalšiu triedu, ktorá musí rozšíriť 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 kontraktu údajov 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ť asi takto:
{
ModuleInventPurchSales module;
StatusIssue statusIssue;
StatusReceipt statusReceipt
}
Musíte vytvoriť metódu new() na vytváranie inštancií všetkých dátových členov. Ak chcete, môžete zadať niektoré alebo všetky predvolené hodnoty, ale ja som to neurobil.
StatusIssue _statusIssue,
StatusReceipt _statusReceipt)
{
;
super();
module = _module;
statusIssue = _statusIssue;
statusReceipt = _statusReceipt;
}
A tiež by ste mali implementovať metódu parm pre každý dátový člen, ale tie som tu vynechal, pretože som si istý, že viete, ako to urobiť - inak to berme ako cvičenie ;-)
Teraz môžete použiť svoju triedu atribútov na ozdobenie každej zo svojich tried spracovania. Napríklad deklarácie triedy môžu vyzerať takto:
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 si samozrejme môžete pomenovať akokoľvek chcete, dôležité je, že si triedy ozdobíte atribútmi, ktoré zodpovedajú tomu, aké spracovanie robia. (Majte však na pamäti, že pre hierarchiu tried v Dynamics AX existujú konvencie pomenovania a vždy je dobré ich dodržiavať, ak je to možné).
Teraz, keď ste vyzdobili svoje triedy, aby ste identifikovali, aký druh spracovania každá z nich robí, môžete využiť rámec SysExtension na vytváranie inštancií objektov podtried podľa potreby.
Vo svojej super triede (MyProcessor) môžete pridať metódu konštrukcie, ako je táto:
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ímavou časťou - a skutočne predmetom (prepáčte slovnú hračku) celého tohto príspevku - je metóda getClassFromSysAttribute() v triede SysExtensionAppClassFactory. Táto metóda robí to, že akceptuje názov supertriedy hierarchie (a táto supertrieda nemusí byť na vrchole hierarchie, jednoducho to znamená, že vhodné budú iba triedy rozširujúce túto triedu) a objekt atribútu.
Potom vráti objekt triedy, ktorý rozširuje špecifikovanú supertriedu a je ozdobený zodpovedajúcim atribútom.
K metóde konštrukcie môžete samozrejme pridať toľko ďalšej validácie alebo logiky, koľko chcete, ale dôležité je, že po implementácii by ste túto metódu už nikdy nemali upravovať. Do hierarchie môžete pridať podtriedy a pokiaľ sa uistíte, že ich vhodne vyzdobíte, metóda konštrukcie ich nájde, aj keď v čase, keď bola napísaná, neexistovali.
A čo výkon? Úprimne, nepokúšal som sa to porovnávať, ale mám pocit, že to pravdepodobne funguje horšie ako klasický dizajn príkazu prepínača. 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, by som sa tým príliš netrápil.
Samozrejme, ak implementujete niečo, čo si bude vyžadovať rýchle vytvorenie tisícok objektov, možno budete chcieť ďalej skúmať, ale v klasických prípadoch, keď len vytvoríte inštanciu jedného objektu, aby ste vykonali nejaké zdĺhavé spracovanie, pochybujem, že to bude záležať. Vzhľadom na môj tip na riešenie problémov (ďalší odsek) sa zdá, že rámec SysExtension sa spolieha na ukladanie do vyrovnávacej pamäte, takže v spustenom systéme pochybujem, že má výrazný zásah do výkonu. Riešenie problémov: Ak metóda konštrukcie nenájde vaše podtriedy, hoci 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 na serveri. Nemalo by byť potrebné reštartovať AOS, ale môže to byť posledná možnosť.