Miklix

การใช้เฟรมเวิร์ก SysExtension เพื่อค้นหาว่าคลาสย่อยที่จะสร้างอินสแตนซ์ใน Dynamics AX 2012

ที่ตีพิมพ์: 16 กุมภาพันธ์ 2025 เวลา 0 นาฬิกา 26 นาที 09 วินาที UTC

บทความนี้อธิบายวิธีการใช้เฟรมเวิร์ก SysExtension ที่ไม่ค่อยมีใครรู้จักใน Dynamics AX 2012 และ Dynamics 365 for Operations เพื่อสร้างอินสแตนซ์คลาสย่อยตามการตกแต่งแอตทริบิวต์ ซึ่งช่วยให้สามารถออกแบบลําดับชั้นของคลาสการประมวลผลที่ขยายได้ง่าย


หน้าเพจนี้ได้รับการแปลจากเครื่องคอมพิวเตอร์จากภาษาอังกฤษ เพื่อให้ทุกคนเข้าถึงได้มากที่สุด น่าเสียดายที่การแปลด้วยเครื่องยังไม่ถือเป็นเทคโนโลยีที่สมบูรณ์แบบ จึงอาจเกิดข้อผิดพลาดได้ หากต้องการ คุณสามารถดูเวอร์ชันภาษาอังกฤษต้นฉบับได้ที่นี่:

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

ข้อมูลในโพสต์นี้ขึ้นอยู่กับ Dynamics AX 2012 R3 อาจใช้ได้หรือไม่ถูกต้องสําหรับเวอร์ชันอื่น (อัปเดต: ฉันสามารถยืนยันได้ว่าข้อมูลในบทความนี้ใช้ได้กับ Dynamics 365 for Operations)

เมื่อใช้คลาสการประมวลผลใน Dynamics AX คุณมักจะต้องเผชิญกับการสร้างลําดับชั้นของคลาสที่แต่ละคลาสย่อยสอดคล้องกับค่า enum หรือมีการเชื่อมโยงข้อมูลอื่นๆ การออกแบบแบบคลาสสิกคือการมีวิธีการสร้างในซุปเปอร์คลาสซึ่งมีสวิตช์ที่กําหนดว่าคลาสใดที่จะสร้างอินสแตนซ์ตามอินพุต

โดยหลักการแล้ววิธีนี้ใช้ได้ดี แต่ถ้าคุณมีอินพุตที่เป็นไปได้มากมาย (องค์ประกอบจํานวนมากในอีนัมหรือบางทีอินพุตอาจเป็นการรวมกันของค่าที่แตกต่างกันหลายค่า) มันอาจกลายเป็นเรื่องน่าเบื่อและมีแนวโน้มที่จะเกิดข้อผิดพลาดในการบํารุงรักษาและการออกแบบมักจะมีข้อเสียที่คุณจะต้องแก้ไขวิธีการสร้างดังกล่าวหากคุณเคยเพิ่มคลาสย่อยใหม่หรือทําการเปลี่ยนแปลงที่ควรใช้คลาสย่อยตามอินพุต

โชคดีที่มีวิธีที่สง่างามกว่ามาก แต่น่าเสียดายที่ยังไม่ค่อยมีใครรู้จักมากในการทําเช่นนี้ นั่นคือการใช้เฟรมเวิร์ก SysExtension

เฟรมเวิร์กนี้ใช้ประโยชน์จากแอตทริบิวต์ที่คุณสามารถใช้ในการตกแต่งคลาสย่อยของคุณเพื่อให้ระบบสามารถทราบได้ว่าควรใช้คลาสย่อยใดในการจัดการอะไร คุณยังคงต้องการวิธีการสร้าง แต่ถ้าทําอย่างถูกต้องคุณจะไม่ต้องแก้ไขเมื่อเพิ่มคลาสย่อยใหม่

ลองดูตัวอย่างในจินตนาการและสมมติว่าคุณจะใช้ลําดับชั้นที่ทําการประมวลผลบางอย่างตามตาราง InventTrans การประมวลผลที่ต้องทําขึ้นอยู่กับ StatusReceipt และ StatusIssue ของระเบียน รวมทั้งว่าระเบียนนั้นเกี่ยวข้องกับ SalesLine, PurchLine หรือไม่มีทั้งสองอย่าง ตอนนี้คุณกําลังดูชุดค่าผสมที่แตกต่างกันมากมาย

สมมติว่าคุณรู้ว่าตอนนี้คุณต้องจัดการกับชุดค่าผสมเพียงไม่กี่ชุด แต่คุณยังรู้ด้วยว่าคุณจะถูกขอให้สามารถจัดการกับชุดค่าผสมได้มากขึ้นเรื่อย ๆ เมื่อเวลาผ่านไป

ขอให้ค่อนข้างเรียบง่ายและบอกว่าสําหรับตอนนี้คุณต้องจัดการเรกคอร์ดที่เกี่ยวข้องกับ SalesLine ที่มี StatusIssue เป็น ReservPhysical หรือ ReservOrdered ชุดค่าผสมอื่น ๆ ทั้งหมดสามารถละเว้นได้ในตอนนี้ แต่เนื่องจากคุณรู้ว่าคุณจะต้องจัดการในภายหลังคุณจะต้องออกแบบโค้ดของคุณในลักษณะที่ทําให้สามารถขยายได้ง่าย

ลําดับชั้นของคุณอาจมีลักษณะดังนี้ในตอนนี้:

  • MyProcessor
    • MyProcessor_Sales
      • MyProcessor_Sales_ReservOrdered
      • MyProcessor_Sales_ReservPhysical

ตอนนี้คุณสามารถใช้วิธีการในซุปเปอร์คลาสที่สร้างอินสแตนซ์คลาสย่อยตาม ModuleInventPurchSales และอีนัม StatusIssue ได้อย่างง่ายดาย แต่คุณจะต้องแก้ไขซุปเปอร์คลาสทุกครั้งที่คุณเพิ่มคลาสย่อย และนั่นไม่ใช่แนวคิดของการสืบทอดในการเขียนโปรแกรมเชิงวัตถุ ท้ายที่สุด คุณไม่จําเป็นต้องแก้ไข RunBaseBatch หรือ SysOperationServiceBase ทุกครั้งที่คุณเพิ่มชุดงานใหม่

คุณสามารถใช้เฟรมเวิร์ก SysExtension แทนได้ ซึ่งคุณจะต้องเพิ่มคลาสอื่นซึ่งจําเป็นต้องขยาย SysAttribute คลาสนี้จะถูกใช้เป็นแอตทริบิวต์ที่คุณสามารถตกแต่งคลาสการประมวลผลของคุณได้

คลาสนี้คล้ายกับวิธีที่คุณจะสร้างคลาสสัญญาข้อมูลสําหรับการใช้งาน SysOperation โดยจะมีสมาชิกข้อมูลและเมธอด parm สําหรับการรับและตั้งค่าเหล่านั้น

ในกรณีของเรา ClassDeclaration อาจมีลักษณะดังนี้:

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

คุณต้องสร้างเมธอด new() สําหรับอินสแตนซ์สมาชิกข้อมูลทั้งหมด หากคุณต้องการคุณสามารถให้ค่าเริ่มต้นบางส่วนหรือทั้งหมดได้ แต่ฉันยังไม่ได้ทําเช่นนั้น

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

    super();

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

และคุณควรใช้วิธีการ parm สําหรับสมาชิกข้อมูลแต่ละตัว แต่ฉันได้ละเว้นสิ่งเหล่านี้ไว้ที่นี่เพราะฉันแน่ใจว่าคุณรู้วิธีทํา - มิฉะนั้น ให้พิจารณาว่าเป็นแบบฝึกหัด ;-)

ตอนนี้คุณสามารถใช้คลาสแอตทริบิวต์ของคุณเพื่อตกแต่งแต่ละคลาสการประมวลผลของคุณ ตัวอย่างเช่น การประกาศคลาสอาจมีลักษณะดังนี้:

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

แน่นอนว่าคุณสามารถตั้งชื่อคลาสของคุณในแบบที่คุณต้องการส่วนสําคัญคือคุณตกแต่งคลาสของคุณด้วยแอตทริบิวต์ที่สอดคล้องกับประเภทของการประมวลผลที่พวกเขาทํา (แต่โปรดทราบว่ามีแบบแผนการตั้งชื่อสําหรับลําดับชั้นของคลาสใน Dynamics AX และเป็นความคิดที่ดีเสมอที่จะปฏิบัติตามสิ่งเหล่านั้น ถ้าเป็นไปได้)

ตอนนี้คุณได้ตกแต่งคลาสของคุณเพื่อระบุว่าแต่ละคลาสทําการประมวลผลประเภทใดคุณสามารถใช้ประโยชน์จากเฟรมเวิร์ก SysExtension เพื่อสร้างอินสแตนซ์วัตถุของคลาสย่อยได้ตามต้องการ

ในคลาสซุปเปอร์ของคุณ (MyProcessor) คุณสามารถเพิ่มวิธีการสร้างได้ดังนี้:

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

ส่วนที่น่าสนใจจริงๆ - และจริงๆ แล้ววัตถุ (ขอโทษการเล่นสํานวน) ของโพสต์ทั้งหมดนี้คือเมธอด getClassFromSysAttribute() ในคลาส SysExtensionAppClassFactory สิ่งที่เมธอดนี้ทําคือยอมรับชื่อของคลาสซุปเปอร์ของลําดับชั้น (และคลาสซุปเปอร์นี้ไม่จําเป็นต้องอยู่ที่ ด้านบนสุด ของลําดับชั้น หมายความว่าเฉพาะคลาสที่ขยายคลาสนี้เท่านั้นที่มีสิทธิ์) และวัตถุแอตทริบิวต์

จากนั้นจะส่งคืนวัตถุของคลาสที่ขยายคลาสพิเศษที่ระบุ และ ตกแต่งด้วยแอตทริบิวต์ที่สอดคล้องกัน

เห็นได้ชัดว่าคุณสามารถเพิ่มการตรวจสอบความถูกต้องหรือตรรกะเพิ่มเติมให้กับวิธีการสร้างได้มากเท่าที่คุณต้องการ แต่ประเด็นสําคัญที่นี่คือเมื่อนําไปใช้แล้วคุณไม่ควรต้องแก้ไขวิธีนี้อีก คุณสามารถเพิ่มคลาสย่อยลงในลําดับชั้นและตราบใดที่คุณแน่ใจว่าได้ตกแต่งอย่างเหมาะสมวิธีการสร้างจะค้นหาแม้ว่าจะไม่มีอยู่จริงเมื่อเขียนก็ตาม

แล้วประสิทธิภาพล่ะ? ฉันไม่ได้พยายามเปรียบเทียบมัน แต่ความรู้สึกของฉันคือสิ่งนี้ อาจ ทํางานได้แย่กว่าการออกแบบคําสั่งสวิตช์แบบคลาสสิก อย่างไรก็ตามเมื่อพิจารณาว่าปัญหาด้านประสิทธิภาพส่วนใหญ่ใน Dynamics AX เกิดจากการเข้าถึงฐานข้อมูลฉันจะไม่กังวลเกี่ยวกับเรื่องนี้มากเกินไป

แน่นอนว่าหากคุณกําลังใช้บางสิ่งที่ต้องใช้วัตถุหลายพันรายการเพื่อสร้างอย่างรวดเร็วคุณอาจต้องการตรวจสอบเพิ่มเติม แต่ในกรณีคลาสสิกที่คุณเพียงแค่สร้างอินสแตนซ์วัตถุเดียวเพื่อทําการประมวลผลที่ยาวนานฉันสงสัยว่ามันจะมีความสําคัญ นอกจากนี้เมื่อพิจารณาถึงเคล็ดลับการแก้ไขปัญหาของฉัน (ย่อหน้าถัดไป) ดูเหมือนว่าเฟรมเวิร์ก SysExtension อาศัยการแคชดังนั้นในระบบที่ทํางานอยู่ฉันสงสัยว่ามันมีผลกระทบด้านประสิทธิภาพอย่างมีนัยสําคัญ การแก้ไขปัญหา: หากวิธีการสร้างไม่พบคลาสย่อยของคุณแม้ว่าคุณจะแน่ใจว่าคลาสย่อยได้รับการตกแต่งอย่างถูกต้องอาจเป็นปัญหาการแคช ลองล้างแคชทั้งบนไคลเอ็นต์และเซิร์ฟเวอร์ ไม่จําเป็นต้องรีสตาร์ท AOS จริงๆ แต่อาจเป็นทางเลือกสุดท้าย

แชร์บนบลูสกายแชร์บนเฟสบุ๊คแชร์บน LinkedInแชร์บน Tumblrแชร์บน Xแชร์บน LinkedInปักหมุดบน Pinterest

มิคเคล บัง คริสเตนเซ่น

เกี่ยวกับผู้เขียน

มิคเคล บัง คริสเตนเซ่น
ไมเคิล คือผู้สร้างและเจ้าของเว็บไซต์ miklix.com เขามีประสบการณ์เป็นโปรแกรมเมอร์/นักพัฒนาซอฟต์แวร์คอมพิวเตอร์มืออาชีพมากว่า 20 ปี และปัจจุบันทำงานเต็มเวลาให้กับบริษัทไอทีขนาดใหญ่แห่งหนึ่งในยุโรป เมื่อไม่ได้เขียนบล็อก เขาจะใช้เวลาว่างไปกับความสนใจ งานอดิเรก และกิจกรรมต่างๆ มากมาย ซึ่งในระดับหนึ่งอาจสะท้อนให้เห็นได้จากหัวข้อต่างๆ มากมายที่กล่าวถึงในเว็บไซต์นี้