Miklix

استخدام إطار عمل SysExtension لمعرفة الفئة الفرعية التي يجب إنشاؤها في Dynamics AX 2012

نُشرت: ١٦ فبراير ٢٠٢٥ م في ١٢:٢٥:٢٢ ص UTC
آخر تحديث: ١٢ يناير ٢٠٢٦ م في ٨:٤٢:٤٧ ص 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، غالبًا ما تواجه إنشاء تسلسل هرمي للفئات، حيث تتوافق كل فئة فرعية مع قيمة تعدادية أو ترتبط ببيانات أخرى. يتمثل التصميم التقليدي في وجود دالة إنشاء في الفئة الأصلية، تحتوي على شرط يحدد الفئة التي سيتم إنشاء مثيل لها بناءً على المدخلات.

هذا يعمل بشكل جيد من حيث المبدأ، ولكن إذا كان لديك العديد من المدخلات المختلفة المحتملة (العديد من العناصر في تعداد أو ربما يكون المدخل عبارة عن مزيج من عدة قيم مختلفة)، فقد يصبح الأمر شاقًا وعرضة للأخطاء في الصيانة، ودائمًا ما يكون للتصميم عيب يتمثل في أنك ستحتاج إلى تعديل طريقة الإنشاء المذكورة إذا قمت بإضافة فئة فرعية جديدة أو إجراء تغييرات على الفئة الفرعية التي يجب استخدامها بناءً على المدخلات.

لحسن الحظ، هناك طريقة أكثر أناقة، ولكنها للأسف أقل شهرة، للقيام بذلك، وهي استخدام إطار عمل SysExtension.

يستفيد هذا الإطار من السمات التي يمكنك استخدامها لتزيين فئاتك الفرعية، مما يُمكّن النظام من تحديد الفئة الفرعية المناسبة لكل مهمة. ستحتاج إلى دالة إنشاء، ولكن إذا تم إنشاؤها بشكل صحيح، فلن تحتاج إلى تعديلها عند إضافة فئات فرعية جديدة.

لنفترض مثالاً افتراضياً، ولنفترض أنك ستُنشئ هيكلاً هرمياً يُجري نوعاً من المعالجة استناداً إلى جدول InventTrans. وتعتمد المعالجة المُختارة على حالتي الاستلام والإصدار للسجلات، بالإضافة إلى ما إذا كانت هذه السجلات مرتبطة بجدول المبيعات أو جدول المشتريات أو غير ذلك. أنت الآن أمام العديد من الاحتمالات.

لنفترض إذن أنك تعلم أنك تحتاج في الوقت الحالي إلى التعامل مع عدد قليل من التركيبات، ولكنك تعلم أيضًا أنه سيُطلب منك أن تكون قادرًا على التعامل مع المزيد والمزيد من التركيبات بمرور الوقت.

لنبقي الأمر بسيطًا نسبيًا ولنقل أنك تحتاج في الوقت الحالي فقط إلى التعامل مع السجلات المتعلقة بـ SalesLine مع StatusIssue من ReservPhysical أو ReservOrdered، ويمكن تجاهل جميع التركيبات الأخرى في الوقت الحالي، ولكن بما أنك تعلم أنك ستضطر إلى التعامل معها لاحقًا، فستحتاج إلى تصميم التعليمات البرمجية الخاصة بك بطريقة تجعلها قابلة للتوسيع بسهولة.

قد يبدو هيكلك الهرمي على هذا النحو في الوقت الحالي:

  • معالجي معالجي_المبيعات معالجي_المبيعات_الحجز_المطلوب معالجي_المبيعات_الحجز_الفعلي

يمكنك الآن بسهولة تنفيذ دالة في الفئة الأصلية لإنشاء فئة فرعية بناءً على تعداد ModuleInventPurchSales وStatusIssue. لكنك ستحتاج حينها إلى تعديل الفئة الأصلية في كل مرة تضيف فيها فئة فرعية، وهذا لا يتماشى مع فكرة الوراثة في البرمجة كائنية التوجه. ففي النهاية، لستَ بحاجة إلى تعديل RunBaseBatch أو SysOperationServiceBase في كل مرة تضيف فيها مهمة دفعية جديدة.

بدلاً من ذلك، يمكنك استخدام إطار عمل SysExtension. سيتطلب ذلك إضافة فئة أخرى، والتي يجب أن ترث من SysAttribute. ستُستخدم هذه الفئة كسمة يمكنك تزيين فئات المعالجة الخاصة بك بها.

هذا الصنف مشابه جدًا لكيفية إنشاء صنف عقد البيانات لتنفيذ SysOperation، حيث أنه سيحتوي على بعض أعضاء البيانات وطرق المعلمات للحصول على تلك القيم وتعيينها.

في حالتنا، قد يبدو تعريف الفئة كالتالي:

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 يعتمد على التخزين المؤقت، لذا أشك في أنه سيؤثر بشكل ملحوظ على أداء النظام قيد التشغيل.

استكشاف الأخطاء وإصلاحها: إذا لم يعثر مُنشئ الفئات الفرعية على فئاتك الفرعية رغم تأكدك من تزيينها بشكل صحيح، فقد تكون المشكلة متعلقة بالتخزين المؤقت. حاول مسح ذاكرة التخزين المؤقت على كلٍ من العميل والخادم. ليس من الضروري إعادة تشغيل نظام التشغيل، ولكن قد يكون هذا هو الحل الأخير.

قراءات إضافية

إذا أعجبك هذا المنشور، فقد تعجبك أيضًا هذه الاقتراحات:


شارك على بلوسكايشارك على الفيسبوكشارك على لينكدإنشارك على تمبلرشارك على إكسشارك على لينكدإنثبت على بينتريست

ميكيل كريستنسن

عن المؤلف

ميكيل كريستنسن
ميكيل هو مؤسس ومالك موقع miklix.com. يتمتع بخبرة تزيد عن 20 عامًا كمبرمج كمبيوتر/مطور برامج محترف ويعمل حاليًا بدوام كامل في إحدى شركات تكنولوجيا المعلومات الأوروبية الكبرى. عندما لا يقوم بالتدوين، يقضي وقت فراغه في مجموعة واسعة من الاهتمامات والهوايات والأنشطة، والتي قد تنعكس إلى حد ما في تنوع الموضوعات التي يغطيها هذا الموقع.