การใช้เฟรมเวิร์ก 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
- MyProcessor_Sales
ตอนนี้คุณสามารถใช้วิธีการในซุปเปอร์คลาสที่สร้างอินสแตนซ์คลาสย่อยตาม ModuleInventPurchSales และอีนัม StatusIssue ได้อย่างง่ายดาย แต่คุณจะต้องแก้ไขซุปเปอร์คลาสทุกครั้งที่คุณเพิ่มคลาสย่อย และนั่นไม่ใช่แนวคิดของการสืบทอดในการเขียนโปรแกรมเชิงวัตถุ ท้ายที่สุด คุณไม่จําเป็นต้องแก้ไข RunBaseBatch หรือ SysOperationServiceBase ทุกครั้งที่คุณเพิ่มชุดงานใหม่
คุณสามารถใช้เฟรมเวิร์ก SysExtension แทนได้ ซึ่งคุณจะต้องเพิ่มคลาสอื่นซึ่งจําเป็นต้องขยาย SysAttribute คลาสนี้จะถูกใช้เป็นแอตทริบิวต์ที่คุณสามารถตกแต่งคลาสการประมวลผลของคุณได้
คลาสนี้คล้ายกับวิธีที่คุณจะสร้างคลาสสัญญาข้อมูลสําหรับการใช้งาน SysOperation โดยจะมีสมาชิกข้อมูลและเมธอด parm สําหรับการรับและตั้งค่าเหล่านั้น
ในกรณีของเรา ClassDeclaration อาจมีลักษณะดังนี้:
{
ModuleInventPurchSales module;
StatusIssue statusIssue;
StatusReceipt statusReceipt
}
คุณต้องสร้างเมธอด new() สําหรับอินสแตนซ์สมาชิกข้อมูลทั้งหมด หากคุณต้องการคุณสามารถให้ค่าเริ่มต้นบางส่วนหรือทั้งหมดได้ แต่ฉันยังไม่ได้ทําเช่นนั้น
StatusIssue _statusIssue,
StatusReceipt _statusReceipt)
{
;
super();
module = _module;
statusIssue = _statusIssue;
statusReceipt = _statusReceipt;
}
และคุณควรใช้วิธีการ parm สําหรับสมาชิกข้อมูลแต่ละตัว แต่ฉันได้ละเว้นสิ่งเหล่านี้ไว้ที่นี่เพราะฉันแน่ใจว่าคุณรู้วิธีทํา - มิฉะนั้น ให้พิจารณาว่าเป็นแบบฝึกหัด ;-)
ตอนนี้คุณสามารถใช้คลาสแอตทริบิวต์ของคุณเพื่อตกแต่งแต่ละคลาสการประมวลผลของคุณ ตัวอย่างเช่น การประกาศคลาสอาจมีลักษณะดังนี้:
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) คุณสามารถเพิ่มวิธีการสร้างได้ดังนี้:
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 จริงๆ แต่อาจเป็นทางเลือกสุดท้าย