Korištenje SysExtension frameworka da biste saznali koju podklasu instancirati u Dynamics AX 2012
Objavljeno: 16. februar 2025. u 00:28:17 UTC
Ovaj članak opisuje kako koristiti malo poznati SysExtension okvir u Dynamics AX 2012 i Dynamics 365 for Operations za instanciranje podklasa na osnovu ukrasa atributa, omogućavajući lako proširiv dizajn hijerarhije klase obrade.
Using the SysExtension Framework to Find Out Which Subclass to Instantiate in Dynamics AX 2012
Informacije u ovom postu su zasnovane na Dynamics AX 2012 R3. Može ili ne mora vrijediti za druge verzije. (Ažuriranje: Mogu potvrditi da informacije u ovom članku vrijede i za Dynamics 365 for Operations)
Kada implementirate klase obrade u Dynamics AX-u, često ste suočeni sa kreiranjem hijerarhije klasa u kojoj svaka podklasa odgovara vrijednosti enuma ili ima neku drugu vezu podataka. Klasičan dizajn je da se u super klasi ima metoda konstrukcije, koja ima prekidač koji određuje koju klasu će instancirati na osnovu ulaza.
Ovo dobro funkcionira u principu, ali ako imate mnogo različitih mogućih ulaza (mnogo elemenata u enumu ili je možda ulaz kombinacija nekoliko različitih vrijednosti), može postati zamoran i sklon greškama za održavanje, a dizajn uvijek ima nedostatak da ćete morati modificirati navedenu metodu konstrukcije ako ikada dodate novu podklasu ili napravite promjene u kojoj podklasi treba koristiti na osnovu kojeg ulaza.
Srećom, postoji mnogo elegantniji, ali nažalost i mnogo manje poznat, način da se to uradi, naime korištenjem SysExtension frameworka.
Ovaj okvir koristi atribute koje možete koristiti za ukrašavanje vaših podklasa kako bi sistem bio u stanju da shvati koja podklasa treba da se koristi za rukovanje štam. I dalje će vam trebati metoda konstrukcije, ali ako se uradi ispravno, nikada je nećete morati mijenjati prilikom dodavanja novih podklasa.
Pogledajmo imaginarni primjer i recimo da ćete implementirati hijerarhiju koja radi neku vrstu obrade na temelju InventTrans tablice. Koja obrada da se uradi zavisi od StatusReceipt i StatusIssue zapisa, kao i od toga da li su zapisi povezani sa SalesLine, PurchLine ili nijedno. Već sada, gledate u mnogo različitih kombinacija.
Recimo onda da znate da za sada trebate nositi samo nekoliko kombinacija, ali također znate da će se od vas tražiti da budete u stanju nositi se sa sve više i više kombinacija tijekom vremena.
Neka bude relativno jednostavno i recimo da za sada samo trebate rukovati zapisima koji se odnose na SalesLine sa StatusIssue od ReservPhysical ili ReservOrdered, sve ostale kombinacije mogu biti ignorisane za sada, ali pošto znate da ćete morati da ih obradite kasnije, vi ćete želeti da dizajnirate svoj kod na način koji ga čini lako proširivim.
Vaša hijerarhija za sada može izgledati ovako:
- MyProcessor
- MyProcessor_Sales
- MyProcessor_Sales_ReservOrdered
- MyProcessor_Sales_ReservPhysical
- MyProcessor_Sales
Sada, možete lako implementirati metodu u super klasi koja instancira podklasu zasnovanu na ModuleInventPurchSales i StatusIssue enumu. Ali tada ćete morati modificirati super klasu svaki put kada dodate podklasu, a to zapravo nije ideja nasljeđivanja u objektno orijentiranom programiranju. Na kraju krajeva, ne morate mijenjati RunBaseBatch ili SysOperationServiceBase svaki put kada dodate novi batch posao.
Umjesto toga, možete koristiti SysExtension framework. To će zahtijevati da dodate još jednu klasu, koja treba proširiti SysAttribute. Ova klasa će se koristiti kao atribut kojim možete ukrasiti svoje časove obrade.
Ova klasa je vrlo slična načinu na koji biste napravili klasu ugovora podataka za implementaciju SysOperation-a, u tome što će imati neke članove podataka i parm metode za dobivanje i postavljanje tih vrijednosti.
U našem slučaju, ClassDeclaration može izgledati otprilike ovako:
{
ModuleInventPurchSales module;
StatusIssue statusIssue;
StatusReceipt statusReceipt
}
Morate napraviti new() metodu za instanciranje svih članova podataka. Ako želite, možete dati neke ili sve od njih podrazumevane vrednosti, ali ja to nisam uradio.
StatusIssue _statusIssue,
StatusReceipt _statusReceipt)
{
;
super();
module = _module;
statusIssue = _statusIssue;
statusReceipt = _statusReceipt;
}
I također biste trebali implementirati parm metodu za svakog člana podataka, ali ja sam ih ovdje izostavio jer sam siguran da znate kako se to radi - inače, smatrajmo to vježbom ;-)
Sada možete koristiti svoju klasu atributa za ukrašavanje svake od vaših klasa obrade. Na primjer, deklaracije klase mogu izgledati ovako:
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
{
}
Naravno, možete imenovati svoje klase kako god želite, važan dio ovdje je da ukrasite svoje klase atributima koji odgovaraju vrsti obrade koju rade. (Ali imajte na umu da postoje konvencije imenovanja za hijerarhije klasa u Dynamics AX-u i uvijek je dobra ideja slijediti ih, ako je moguće).
Sada kada ste ukrasili svoje klase kako biste identificirali kakvu vrstu obrade svaka od njih radi, možete iskoristiti SysExtension framework za instanciranje objekata podklasa po potrebi.
U vašoj super klasi (MyProcessor), možete dodati konstruktivnu metodu poput ove:
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;
}
Zaista zanimljiv dio - i stvarno objekt (oprostite na igri riječi) cijelog ovog posta - je getClassFromSysAttribute() metoda u klasi SysExtensionAppClassFactory. Ono što ova metoda radi je da prihvata ime super klase hijerarhije (a ova super klasa ne mora biti na vrhu hijerarhije; to jednostavno znači da će samo klase koje proširuju ovu klasu biti podobne) i atributni objekt.
Zatim vraća objekt klase koji proširuje specificiranu super klasu i ukrašen je odgovarajućim atributom.
Očigledno možete dodati onoliko daljnje validacije ili logike u konstruktivnu metodu koliko želite, ali važno je da jednom implementirana, nikada više ne biste trebali modificirati ovu metodu. Možete dodati podklase u hijerarhiju i sve dok se pobrinete da ih ukrasite na odgovarajući način, metoda konstrukcije će ih pronaći iako nisu postojale kada je napisana.
Šta je sa performansama? Iskreno nisam pokušao da ga benchmark, ali moj osjećaj je da ovo vjerovatno radi lošije od klasičnog dizajna prekidača. Međutim, s obzirom na to da je daleko većina problema sa performansama u Dynamics AX-u uzrokovana pristupom bazi podataka, ne bih se previše brinuo o tome.
Naravno, ako implementirate nešto što će zahtijevati hiljade objekata da se brzo kreiraju, možda ćete htjeti dalje istraživati, ali u klasičnim slučajevima gdje samo instancirate jedan objekt da biste napravili neku dugotrajnu obradu, sumnjam da će to biti važno. Također, s obzirom na moj savjet za rješavanje problema (sljedeći paragraf), čini se da se SysExtension framework oslanja na keširanje, tako da u pokrenutom sistemu sumnjam da ima značajan utjecaj na performanse. Rješavanje problema: Ako metoda konstrukcije ne pronađe vaše podklase iako ste sigurni da su ispravno ukrašene, to može biti problem keširanja. Pokušajte očistiti keš i na klijentu i na serveru. Ne bi trebalo biti potrebno zapravo ponovno pokrenuti AOS, ali to može biti posljednje sredstvo.