Uporaba ogrodja SysExtension Framework, da ugotovite, kateri podrazred ustvariti v Dynamics AX 2012
Objavljeno: 16. februar 2025 ob 12:25:59 dop. UTC
Ta članek opisuje, kako uporabiti malo znano ogrodje SysExtension v programih Dynamics AX 2012 in Dynamics 365 for Operations za instanciranje podrazredov na podlagi okraskov atributov, kar omogoča preprosto razširljivo zasnovo hierarhije razredov obdelave.
Using the SysExtension Framework to Find Out Which Subclass to Instantiate in Dynamics AX 2012
Informacije v tej objavi temeljijo na Dynamics AX 2012 R3. Lahko velja ali ne velja za druge različice. (Posodobitev: lahko potrdim, da so informacije v tem članku veljavne tudi za Dynamics 365 for Operations)
Pri izvajanju razredov obdelave v Dynamics AX se pogosto soočate z ustvarjanjem hierarhije razredov, v kateri vsak podrazred ustreza vrednosti enum ali ima kakšno drugo povezavo podatkov. Klasična zasnova je, da ima nato v nadrazredu metodo konstrukta, ki ima stikalo, ki določa, kateri razred naj se instancira na podlagi vnosa.
To načeloma deluje dobro, vendar če imate veliko različnih možnih vnosov (veliko elementov v enum ali je morda vnos kombinacija več različnih vrednosti), lahko postane vzdrževanje dolgočasno in nagnjeno k napakam, zasnova pa ima vedno to pomanjkljivost, da boste morali spremeniti omenjeno metodo konstrukcije, če boste kdaj dodali nov podrazred ali spremenili, kateri podrazred naj se uporablja glede na kateri vnos.
Na srečo obstaja veliko bolj eleganten, a žal tudi veliko manj znan način za to, in sicer z uporabo ogrodja SysExtension.
To ogrodje izkorišča prednosti atributov, ki jih lahko uporabite za okrasitev svojih podrazredov, da lahko sistem ugotovi, kateri podrazred naj se uporabi za ravnanje s čim. Še vedno boste potrebovali metodo konstrukta, a če je pravilno izvedena, vam je pri dodajanju novih podrazredov nikoli ne bo treba spreminjati.
Poglejmo namišljen primer in recimo, da boste implementirali hierarhijo, ki izvaja nekakšno obdelavo na podlagi tabele InventTrans. Katero obdelavo je treba izvesti, je odvisno od StatusReceipt in StatusIssue zapisov, pa tudi od tega, ali so zapisi povezani s SalesLine, PurchLine ali nobenim od njih. Že zdaj si ogledujete veliko različnih kombinacij.
Recimo torej, da veste, da morate za zdaj upravljati le s peščico kombinacij, vendar veste tudi, da boste morali sčasoma upravljati vedno več kombinacij.
Naj bo razmeroma preprosto in povejmo, da morate zaenkrat obravnavati samo zapise, povezane s SalesLine, s StatusIssue ReservPhysical ali ReservOrdered, vse druge kombinacije lahko za zdaj prezrete, a ker veste, da jih boste morali obravnavati pozneje, boste želeli oblikovati svojo kodo tako, da bo zlahka razširljiva.
Vaša hierarhija je lahko trenutno videti nekako takole:
- MojProcesor
- MyProcessor_Sales
- MyProcessor_Sales_ReservOrdered
- MyProcessor_Sales_ReservPhysical
- MyProcessor_Sales
Zdaj bi lahko preprosto implementirali metodo v nadrazredu, ki instancira podrazred na podlagi ModuleInventPurchSales in Enum StatusIssue. Toda nato boste morali spremeniti nadrazred vsakič, ko dodate podrazred, in to pravzaprav ni ideja dedovanja v objektno usmerjenem programiranju. Navsezadnje vam ni treba spreminjati RunBaseBatch ali SysOperationServiceBase vsakič, ko dodate novo paketno opravilo.
Namesto tega lahko uporabite ogrodje SysExtension. To bo zahtevalo, da dodate drug razred, ki mora razširiti SysAttribute. Ta razred bo uporabljen kot atribut, s katerim lahko okrasite svoje razrede obdelave.
Ta razred je zelo podoben temu, kako bi naredili razred podatkovne pogodbe za izvedbo SysOperation, saj bo imel nekaj podatkovnih članov in metod parm za pridobivanje in nastavitev teh vrednosti.
V našem primeru je lahko ClassDeclaration videti nekako takole:
{
ModuleInventPurchSales module;
StatusIssue statusIssue;
StatusReceipt statusReceipt
}
Izdelati morate metodo new() za instanciranje vseh podatkovnih članov. Če želite, lahko nekaterim ali vsem podate privzete vrednosti, vendar tega nisem storil.
StatusIssue _statusIssue,
StatusReceipt _statusReceipt)
{
;
super();
module = _module;
statusIssue = _statusIssue;
statusReceipt = _statusReceipt;
}
Prav tako bi morali implementirati metodo parm za vsakega podatkovnega člana, vendar sem jih tukaj izpustil, saj sem prepričan, da veste, kako to storiti - drugače pa to smatrajte za vajo ;-)
Zdaj lahko s svojim razredom atributov okrasite vsakega od svojih razredov obdelave. Na primer, deklaracije razreda bi lahko izgledale takole:
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
{
}
Seveda lahko svoje razrede poimenujete kakor koli želite, pomemben del pri tem je, da svoje razrede okrasite z atributi, ki ustrezajo vrsti obdelave, ki jo izvajajo. (Vendar ne pozabite, da obstajajo konvencije o poimenovanju za hierarhije razredov v Dynamics AX in jih je vedno dobro upoštevati, če je mogoče).
Zdaj, ko ste okrasili svoje razrede, da ugotovite, kakšno vrsto obdelave izvaja vsak od njih, lahko izkoristite ogrodje SysExtension, da po potrebi ustvarite primerke predmetov podrazredov.
V svoj nadrazred (MyProcessor) lahko dodate metodo konstrukcije, kot je ta:
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;
}
Resnično zanimiv del - in pravzaprav predmet (oprostite besedni igri) te celotne objave - je metoda getClassFromSysAttribute() v razredu SysExtensionAppClassFactory. Ta metoda sprejme ime nadrazreda hierarhije (in ni treba, da je ta nadrazred na vrhu hierarhije; to preprosto pomeni, da bodo primerni le razredi, ki razširjajo ta razred) in atributni objekt.
Nato vrne objekt razreda, ki razširja navedeni nadrazred in je okrašen z ustreznim atributom.
Metodi konstrukta lahko seveda dodate toliko nadaljnjega preverjanja veljavnosti ali logike, kot želite, vendar je pomemben zaključek tukaj ta, da vam po implementaciji te metode nikoli več ne bi bilo treba spreminjati. V hierarhijo lahko dodate podrazrede in dokler se prepričate, da jih ustrezno okrasite, jih bo metoda konstrukta našla, čeprav še niso obstajali, ko je bila napisana.
Kaj pa uspešnost? Resnično ga nisem poskušal primerjati, vendar imam občutek, da se to verjetno obnese slabše kot klasična zasnova izjave switch. Vendar glede na to, da daleč največ težav z zmogljivostjo v Dynamics AX povzroči dostop do zbirke podatkov, me to ne bi preveč skrbelo.
Seveda, če implementirate nekaj, kar bo zahtevalo na tisoče objektov, ki jih je treba hitro ustvariti, boste morda želeli nadalje raziskati, toda v klasičnih primerih, ko samo instancirate en sam objekt za dolgotrajno obdelavo, dvomim, da bo to pomembno. Ob upoštevanju mojega nasveta za odpravljanje težav (naslednji odstavek) se zdi, da se ogrodje SysExtension opira na predpomnjenje, zato dvomim, da ima v delujočem sistemu velik udarec v zmogljivosti. Odpravljanje težav: če metoda konstrukta ne najde vaših podrazredov, čeprav ste prepričani, da so pravilno okrašeni, je morda težava s predpomnjenjem. Poskusite počistiti predpomnilnike na odjemalcu in strežniku. Dejansko znova zagnati AOS ne bi smelo biti potrebno, vendar je to morda zadnja možnost.