Miklix

שימוש במסגרת SysExtension כדי לגלות איזו תת-מחלקה להפעיל ב- Dynamics AX 2012

פורסם: 16 בפברואר 2025 בשעה 0:26:15 UTC
עודכן לאחרונה: 12 בינואר 2026 בשעה 8:43:30 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 או שיש לה צימוד נתונים אחר. תכנון קלאסי הוא לאחר מכן לכלול מתודת בנייה במחלקת העל, הכוללת מתג שקובע איזו מחלקה ליצור מופעים בהתבסס על הקלט.

זה עובד היטב באופן עקרוני, אבל אם יש לך הרבה קלטים אפשריים ושונים (אלמנטים רבים ב-enum או אולי הקלט הוא שילוב של כמה ערכים שונים), התחזוקה יכולה להיות מייגעת ונוטה לשגיאות, והעיצוב תמיד טומן בחובו את החיסרון שתצטרך לשנות את שיטת הבנייה האמורה אם אי פעם תוסיף תת-מחלקה חדשה או תבצע שינויים באיזו תת-מחלקה יש להשתמש בהתבסס על איזה קלט.

למרבה המזל, יש דרך הרבה יותר אלגנטית, אך למרבה הצער גם הרבה פחות ידועה, לעשות זאת, כלומר באמצעות שימוש במסגרת SysExtension.

מסגרת זו מנצלת תכונות בהן ניתן להשתמש כדי לקשט את תת-המחלקות שלכם כדי לאפשר למערכת להבין איזו תת-מחלקה צריכה לשמש לטיפול במה. עדיין תצטרכו מתודת בנייה, אך אם תעשו זאת נכון, לעולם לא תצטרכו לשנות אותה בעת הוספת תת-מחלקות חדשות.

בואו נסתכל על דוגמה דמיונית ונניח שאתם הולכים ליישם היררכיה שמבצעת עיבוד כלשהו המבוסס על טבלת InventTrans. איזה עיבוד לעשות תלוי ב-StatusReceipt וב-StatusIssue של הרשומות, וכן בשאלה האם הרשומות קשורות ל-SalesLine, ל-PurchLine או לאף אחת מהן. כבר עכשיו, אתם מסתכלים על הרבה שילובים שונים.

נניח שאתם יודעים שכרגע אתם צריכים להתמודד רק עם קומץ מהצירופים, אבל אתם גם יודעים שתתבקשו להתמודד עם עוד ועוד צירופים עם הזמן.

בואו נשמור על זה פשוט יחסית ונאמר שבינתיים אתם צריכים לטפל רק ברשומות הקשורות ל-SalesLine עם StatusIssue של ReservPhysical או ReservOrdered, ניתן להתעלם מכל שאר הצירופים לעת עתה, אך מכיוון שאתם יודעים שתצטרכו לטפל בהם בהמשך, תרצו לעצב את הקוד שלכם בצורה שתאפשר להרחבה קלה.

ההיררכיה שלך עשויה להיראות בערך כך כרגע:

  • המעבד שליהמעבד_המכירות_המעבד_המכירות_ההזמנההמעבד_המכירות_הזמנת_המעבד_המכירות_הפיזי

כעת, תוכלו בקלות ליישם מתודה במחלקת העל שיוצרת תת-מחלקה המבוססת על ModuleInventPurchSales ו-enum של 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. מה שהמתודה הזו עושה זה שהיא מקבלת את שם המחלקה העל של היררכיה (והמחלקה העל הזו לא צריכה להיות בראש ההיררכיה; זה פשוט אומר שרק מחלקות המרחיבות מחלקה זו יהיו זכאיות) ואובייקט attribute.

לאחר מכן הוא מחזיר אובייקט של מחלקה שמרחיבה את מחלקת-העל שצוינה ומעוטרת בתכונה תואמת.

ניתן כמובן להוסיף כמה שיותר אימות או לוגיקה למתודת הבנייה כרצונכם, אך המסקנה החשובה מכאן היא שלאחר הטמעתה, לא תצטרכו לשנות את המתודה הזו שוב. ניתן להוסיף תת-מחלקות להיררכיה, וכל עוד תוודאו לעטר אותן כראוי, מתודת הבנייה תמצא אותן למרות שלא היו קיימות כשהיא נכתבה.

מה לגבי ביצועים? בכנות, לא ניסיתי לעשות זאת בביצועים, אבל תחושת הבטן שלי היא שזה כנראה מתפקד גרוע יותר מעיצוב משפט ה-switch הקלאסי. עם זאת, בהתחשב בכך שרוב בעיות הביצועים ב-Dynamics AX נגרמות מגישה למסד נתונים, לא הייתי דואג יותר מדי בקשר לזה.

כמובן, אם אתם מיישמים משהו שידרוש יצירה מהירה של אלפי אובייקטים, ייתכן שתרצו לחקור לעומק, אבל במקרים הקלאסיים שבהם אתם פשוט יוצרים מופע של אובייקט בודד כדי לבצע עיבוד ארוך, אני בספק אם זה משנה. כמו כן, בהתחשב בעצה שלי לפתרון בעיות (פסקה הבאה), נראה שמסגרת SysExtension מסתמכת על אחסון במטמון, כך שבמערכת רצה אני בספק אם יש לה פגיעה משמעותית בביצועים.

פתרון בעיות: אם שיטת הבנייה לא מוצאת את תת-המחלקות שלך למרות שאתה בטוח שהן מעוטרות כהלכה, ייתכן שמדובר בבעיית אחסון במטמון. נסה לנקות מטמונים גם בלקוח וגם בשרת. לא אמור להיות צורך להפעיל מחדש את ה-AOS, אך ייתכן שזהו מוצא אחרון.

קריאה נוספת

אם נהניתם מהפוסט הזה, אולי תאהבו גם את ההצעות הבאות:


שתפו בבלוסקישתפו בפייסבוקשתפו בלינקדאיןשתפו ב-Tumblrשתפו ב-Xשתפו בלינקדאיןהצמד בפינטרסט

מיקל כריסטנסן

על המחבר

מיקל כריסטנסן
מיקל הוא היוצר והבעלים של miklix.com. יש לו למעלה מ-20 שנות ניסיון כמתכנת מחשבים/מפתח תוכנה מקצועי וכיום הוא מועסק במשרה מלאה בתאגיד IT אירופאי גדול. כשהוא לא כותב בלוג, הוא מבלה את זמנו הפנוי במגוון עצום של תחומי עניין, תחביבים ופעילויות, שעשויים לבוא לידי ביטוי במידה מסוימת במגוון הנושאים המכוסים באתר זה.