Miklix

Korištenje okvira SysExtension za otkrivanje koju podklasu instancirati u Dynamics AX 2012

Objavljeno: 16. veljače 2025. u 00:28:19 UTC

Ovaj članak opisuje kako koristiti malo poznati okvir SysExtension u sustavima Dynamics AX 2012 i Dynamics 365 for Operations za instanciranje podklasa na temelju dekoracija atributa, čime se omogućuje lako proširiv dizajn hijerarhije klasa obrade.


Ova je stranica strojno prevedena s engleskog kako bi bila dostupna što većem broju ljudi. Nažalost, strojno prevođenje još nije usavršena tehnologija pa se mogu pojaviti pogreške. Ako želite, izvornu englesku verziju možete pogledati ovdje:

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

Informacije u ovom postu temelje se na Dynamics AX 2012 R3. Može, ali i 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, često se suočavate sa stvaranjem hijerarhije klasa u kojoj svaka podklasa odgovara enum vrijednosti ili ima neki drugi spoj podataka. Klasični dizajn je onda imati konstruktivnu metodu u super klasi, koja ima prekidač koji određuje koju klasu instancirati na temelju ulaza.

Ovo u principu dobro funkcionira, 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 zamorno i sklono pogreškama za održavanje, a dizajn uvijek ima nedostatak da ćete morati modificirati navedenu metodu konstrukcije ako ikada dodate novu podklasu ili promijenite koju podklasu treba koristiti na temelju kojeg unosa.

Srećom, postoji mnogo elegantniji, ali nažalost i mnogo manje poznat način da se to učini, naime korištenjem okvira SysExtension.

Ovaj okvir iskorištava prednosti atributa koje možete koristiti za ukrašavanje svojih podklasa kako bi sustav mogao otkriti koja bi se podklasa trebala koristiti za rukovanje čime. I dalje ćete trebati konstruktivnu metodu, ali ako je ispravno napravite, nikada je nećete morati modificirati kada dodajete nove podklase.

Pogledajmo zamišljeni primjer i recimo da ćete implementirati hijerarhiju koja vrši neku vrstu obrade na temelju tablice InventTrans. Koju obradu izvršiti ovisi o StatusReceipt i StatusIssue zapisa, kao i o tome jesu li zapisi povezani s SalesLine, PurchLine ili ni s jednim. Već sada gledate mnogo različitih kombinacija.

Recimo onda da znate da za sada trebate rukovati samo nekoliko kombinacija, ali također znate da će se od vas tražiti da budete u stanju rukovati sve više i više kombinacija s vremenom.

Neka bude relativno jednostavno i recimo da za sada samo trebate rukovati zapisima koji se odnose na SalesLine sa StatusIssue ReservPhysical ili ReservOrdered, sve druge kombinacije možete zanemariti za sada, ali budući da znate da ćete njima morati rukovati kasnije, htjet ćete dizajnirati svoj kod na način koji ga čini lako proširivim.

Vaša hijerarhija za sada može izgledati otprilike ovako:

  • MojProcesor
    • MojProcesor_Sales
      • MyProcessor_Sales_ReservOrdered
      • MyProcessor_Sales_ReservPhysical

Sada možete jednostavno implementirati metodu u superklasu koja instancira potklasu temeljenu na ModuleInventPurchSales i StatusIssue enum. Ali tada ćete morati modificirati superklasu svaki put kada dodate podklasu, a to zapravo nije ideja nasljeđivanja u objektno orijentiranom programiranju. Uostalom, ne morate modificirati RunBaseBatch ili SysOperationServiceBase svaki put kada dodate novi paketni posao.

Umjesto toga, možete koristiti okvir SysExtension. To će zahtijevati da dodate drugu klasu, koja treba proširiti SysAttribute. Ova će se klasa koristiti kao atribut kojim možete ukrasiti svoje klase obrade.

Ova je klasa vrlo slična načinu na koji biste napravili klasu podatkovnog ugovora za implementaciju SysOperation, jer ć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:

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

Morate napraviti new() metodu za instanciranje svih podatkovnih članova. Ako želite, možete dati neke ili sve zadane vrijednosti, ali ja to nisam učinio.

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

    super();

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

Također biste trebali implementirati metodu parm za svaki podatkovni član, ali ja sam ih ovdje izostavio jer sam siguran da znate kako to učiniti - inače, smatrajmo to vježbom ;-)

Sada možete koristiti svoju klasu atributa za ukrašavanje svake vaše klase obrade. Na primjer, deklaracije klasa mogu izgledati ovako:

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

Možete naravno imenovati svoje klase kako god želite, važan dio ovdje je da svoje klase ukrasite 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 uredili svoje klase kako biste identificirali kakvu obradu svaka od njih radi, možete iskoristiti okvir SysExtension za instanciranje objekata podklasa prema potrebi.

U svoju super klasu (MyProcessor), možete dodati metodu konstrukcije poput ove:

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

Stvarno zanimljiv dio - i zapravo objekt (oprostite na igri riječi) cijelog ovog posta - je metoda getClassFromSysAttribute() u klasi SysExtensionAppClassFactory. Ono što ova metoda radi je da prihvaća naziv super klase hijerarhije (i ta super klasa ne mora biti na vrhu hijerarhije; to jednostavno znači da će samo klase koje proširuju ovu klasu biti prihvatljive) i objekt atributa.

Zatim vraća objekt klase koja proširuje navedenu super klasu i ukrašena je odgovarajućim atributom.

Očigledno je da metodi konstrukcije možete dodati onoliko daljnje provjere valjanosti ili logike koliko god želite, ali važan zaključak je da jednom implementirana, više nikada ne biste trebali modificirati ovu metodu. Možete dodati podklase u hijerarhiju i dokle god se pobrinete da ih prikladno dekorirate, metoda konstrukcije će ih pronaći iako nisu postojale kad je napisana.

Što je s performansama? Iskreno, nisam ga pokušao mjeriti, ali moj osjećaj je da ovo vjerojatno radi lošije od klasičnog dizajna switch statementa. Međutim, s obzirom na to da je daleko većina problema s performansama u Dynamics AX-u uzrokovana pristupom bazi podataka, ne bih se previše brinuo oko toga.

Naravno, ako implementirate nešto što će zahtijevati tisuće objekata da se brzo kreiraju, možda ćete htjeti dalje istraživati, ali u klasičnim slučajevima gdje samo instancirate jedan objekt za dugotrajnu obradu, sumnjam da će to biti važno. Također, uzimajući u obzir moj savjet za rješavanje problema (sljedeći odlomak), čini se da se okvir SysExtension oslanja na predmemoriju, tako da u sustavu koji radi sumnjam da ima značajan pad performansi. Rješavanje problema: Ako metoda konstrukcije ne pronađe vaše potklase iako ste sigurni da su ispravno uređene, možda je problem u predmemoriji. Pokušajte očistiti predmemoriju i na klijentu i na poslužitelju. Ne bi trebalo biti nužno stvarno ponovno pokrenuti AOS, ali to može biti zadnje rješenje.

Podijeli na BlueskyPodijelite na FacebookuPodijelite na LinkedInuPodijelite na TumblrPodijeli na XPodijelite na LinkedInuPrikvači na Pinterest

Mikkel Bang Christensen

O autoru

Mikkel Bang Christensen
Mikkel je kreator i vlasnik miklix.com. Ima više od 20 godina iskustva kao profesionalni računalni programer/razvijač softvera i trenutno je zaposlen na puno radno vrijeme za veliku europsku IT korporaciju. Kada ne piše blog, svoje slobodno vrijeme provodi na široku lepezu interesa, hobija i aktivnosti, što se u određenoj mjeri može odraziti na različite teme obrađene na ovoj web stranici.