Dynamics 365 Business Central: การใช้งาน Hide Payment Method Code ในหน้า General Ledger Setup

ใน Dynamics 365 Business Central, การตั้งค่า General Ledger Setup เป็นขั้นตอนสำคัญสำหรับการกำหนดค่าบัญชีแยกประเภททั่วไปขององค์กรของคุณ. บางครั้งองค์กรอาจต้องการซ่อนฟิลด์ Payment Method Code เพื่อป้องกันไม่ให้ผู้ใช้บางคนเห็นหรือแก้ไขข้อมูลนี้ บทความนี้จะอธิบายวิธีการซ่อน Payment Method Code อย่างละเอียด พร้อมยกตัวอย่างการใช้งาน.

  • ไปที่ไอคอน ค้นหา (รูปแว่นขยาย) ที่มุมบนขวา
  • พิมพ์ “General Ledger Setup” และเลือกจากผลการค้นหา

ตั้งค่าฟิลด์ “Hide Payment Method Code”

ในหน้า General Ledger Setup ค้นหาฟิลด์ “Hide Payment Method Code”

ตั้งค่าเป็น False หรือ No เพื่อแสดงฟิลด์ “Payment Method Code” ตามปกติ

ตัวอย่างเอกสาร Sales Order

ตัวอย่างเอกสาร Purchase Order

ตั้งค่าเป็น True หรือ Yes เพื่อซ่อนฟิลด์ “Payment Method Code” จากหน้าเพจและเอกสารต่าง ๆ

ตัวอย่างเอกสาร Sales Order

ตัวอย่างการทำงาน Source Code หน้า Sales Order

ตัวอย่างเอกสาร Purchase Order

ตัวอย่างการทำงาน Source Code หน้า Purchase Order

สรุป

ฟิลด์ “Hide Payment Method Code” ในหน้า General Ledger Setup ถูกใช้เพื่อควบคุมการแสดงผลของฟิลด์ “Payment Method Code” ภายในระบบ การตั้งค่านี้ช่วยให้คุณสามารถปรับแต่งการทำงานของระบบให้เหมาะสมกับความต้องการขององค์กร ลดความซับซ้อน และป้องกันข้อผิดพลาดที่อาจเกิดขึ้นจากการป้อนข้อมูลที่ไม่ถูกต้อง

Dynamics 365 Business Central: การใช้งาน FlowFields และ FlowFilters ใน AL Programming

ในการพัฒนา Dynamics 365 Business Central ด้วยภาษา AL การเข้าใจ FlowFields และ FlowFilters เป็นสิ่งสำคัญมาก เพราะเป็นเครื่องมือที่ช่วยในการคำนวณและกรองข้อมูลในตารางอย่างมีประสิทธิภาพ บทความนี้จะอธิบายรายละเอียดเกี่ยวกับ FlowFields และ FlowFilters พร้อมตัวอย่างการใช้งาน

FlowFields คืออะไร?

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

  • Sum: การรวมผลรวม
  • Count: การนับจำนวนรายการ
  • Average: การคำนวณค่าเฉลี่ย
  • Min: หาค่าน้อยสุด
  • Max: หาค่ามากสุด
  • Exist: ตรวจสอบการมีอยู่ของรายการ
  • Lookup: ค้นหาค่าในฟิลด์อื่น

1. Sum (การรวมผลรวม)

ตัวอย่าง: คำนวณยอดขายรวมของลูกค้า

การสร้าง FlowField ด้วย CalcFormula แบบ Sum

        field(50000; "Total Sales"; Decimal)
        {
            FieldClass = FlowField;
            CalcFormula = Sum("Sales Line"."Amount" where("Sell-to Customer No." = field("No.")));
            Editable = false;
        }

อธิบาย

  • Sum เป็นฟังก์ชันที่ใช้ในการรวมผลรวมของฟิลด์ที่ระบุ
  • "Sales Line"."Amount" ระบุฟิลด์ Amount จากตาราง Sales Line
  • เงื่อนไข where ("Sell-to Customer No."=field("No.")) คือการเชื่อมโยงกับลูกค้าปัจจุบัน

2. Count (การนับจำนวนรายการ)

ตัวอย่าง: นับจำนวนคำสั่งซื้อของลูกค้า

การสร้าง FlowField ด้วย CalcFormula แบบ Count

        field(50001; "Order Count"; Integer)
        {
            FieldClass = FlowField;
            CalcFormula = Count("Sales Header" where("Sell-to Customer No." = field("No."), "Document Type" = CONST(Order)));
            Caption = 'Order Count';
            Editable = false;
        }

อธิบาย

  • Count ใช้ในการนับจำนวนรายการที่ตรงกับเงื่อนไข
  • "Sales Header" คือตารางที่ใช้ในการนับ
  • เงื่อนไข ("Sell-to Customer No" = field("No."), "Document Type" = CONST(Order)) ระบุว่าต้องเป็นคำสั่งซื้อของลูกค้าปัจจุบันและเป็นประเภทเอกสาร Order

3. Average (การคำนวณค่าเฉลี่ย)

ตัวอย่าง: คำนวณค่าเฉลี่ยยอดขายต่อคำสั่งซื้อของลูกค้า

การสร้าง FlowField ด้วย CalcFormula แบบ Average

        field(50002; "Average Order Amount"; Decimal)
        {
            FieldClass = FlowField;
            CalcFormula = Average("Sales Line"."Amount" where("Sell-to Customer No." = field("No.")));
            Caption = 'Average Order Amount';
            Editable = false;
        }

อธิบาย

  • Average ใช้ในการคำนวณค่าเฉลี่ยของฟิลด์ที่ระบุ
  • ใช้เงื่อนไขเพื่อกรองข้อมูลที่เกี่ยวข้องกับลูกค้าปัจจุบัน

4. Min (หาค่าน้อยสุด)

ตัวอย่าง: หายอดขายน้อยสุดของลูกค้า

การสร้าง FlowField ด้วย CalcFormula แบบ Min

        field(50003; "Minimum Sale Amount"; Decimal)
        {
            FieldClass = FlowField;
            CalcFormula = Min("Sales Line"."Amount" where("Sell-to Customer No." = field("No.")));
            Caption = 'Minimum Sale Amount';
            Editable = false;
        }

อธิบาย

  • Min ใช้ในการหาค่าที่น้อยที่สุดของฟิลด์ที่ระบุ
  • ใช้สำหรับหายอดขายที่น้อยที่สุดในคำสั่งซื้อของลูกค้า

5. Max (หาค่ามากสุด)

ตัวอย่าง: หายอดขายมากสุดของลูกค้า

การสร้าง FlowField ด้วย CalcFormula แบบ Max

        field(50004; "Maximum Sale Amount"; Decimal)
        {
            FieldClass = FlowField;
            CalcFormula = Max("Sales Line"."Amount" where("Sell-to Customer No." = field("No.")));
            Caption = 'Maximum Sale Amount';
            Editable = false;
        }

อธิบาย

  • Max ใช้ในการหาค่าที่มากที่สุดของฟิลด์ที่ระบุ
  • ใช้สำหรับหายอดขายที่มากที่สุดในคำสั่งซื้อของลูกค้า

6. Exist (ตรวจสอบการมีอยู่ของรายการ)

ตัวอย่าง: ตรวจสอบว่าลูกค้ามีคำสั่งซื้อหรือไม่

การสร้าง FlowField ด้วย CalcFormula แบบ Exist

        field(50005; "Has Orders"; Boolean)
        {
            FieldClass = FlowField;
            CalcFormula = Exist("Sales Header" where("Sell-to Customer No." = field("No."), "Document Type" = CONST(Order)));
            Caption = 'Has Orders';
            Editable = false;
        }

อธิบาย

  • Exist จะคืนค่า true หากมีรายการที่ตรงกับเงื่อนไข หรือ false หากไม่มี
  • ใช้ในการตรวจสอบว่าลูกค้ามีคำสั่งซื้อหรือไม่

7. Lookup (ค้นหาค่าในฟิลด์อื่น)

ตัวอย่าง: ดึงข้อมูล Email ของผู้ติดต่อ (Contact) ที่เชื่อมโยงกับลูกค้า (Customer)

การสร้าง FlowField ด้วย CalcFormula แบบ Lookup

        field(50007; "Contact Email"; Text[100])
        {
            FieldClass = FlowField;
            CalcFormula = Lookup(Contact."E-Mail" where("No." = field("Primary Contact No.")));
            Caption = 'Contact Email';
            Editable = false;
        }

อธิบาย

  • Lookup ใช้ในการดึงค่าจากฟิลด์ในตารางอื่น
  • ในกรณีนี้ ดึงค่า E-Mail จากตาราง Contact

การคำนวณค่าใน FlowField

FlowField จะไม่คำนวณค่าอัตโนมัติ ต้องเรียกใช้เมธอด CALCFIELDS เพื่อคำนวณค่า

CustomerRec.CalcFields("Total Sales");

ตัวอย่างการใช้งาน

    var
        CustomerRec: Record Customer;
    begin
        CustomerRec.SetRange("No.", 'CUST001');
        if CustomerRec.FindFirst() then begin
            CustomerRec.CalcFields("Total Sales");
            Message('Total Sales for %1 is %2', CustomerRec."Name", CustomerRec."Total Sales");
        end;
    end;

FlowFilters คืออะไร?

FlowFilters เป็นฟิลด์ชนิดพิเศษที่ใช้ในการกรองข้อมูลสำหรับการคำนวณใน FlowFields โดยไม่เก็บข้อมูลจริง แต่ใช้เป็นตัวกรองชั่วคราว

        field(50001; "Date Filter"; Date)
        {
            FieldClass = FlowFilter;
        }

การใช้งาน FlowFilter ร่วมกับ FlowField

เมื่อเราต้องการคำนวณยอดขายในช่วงวันที่ที่กำหนด เราสามารถใช้ FlowFilter เพื่อกำหนดช่วงวันที่

ตัวอย่างการเรียกใช้ FlowFilter

        field(50000; "Total Sales"; Decimal)
        {
            FieldClass = FlowField;
            CalcFormula = Sum("Sales Line"."Amount" where("Sell-to Customer No." = field("No."),
                                                                "Requested Delivery Date" = field("Date Filter")));
            Editable = false;
        }

ตัวอย่างการใช้งาน FlowFilter ใน Code

 var
        CustomerRec: Record Customer;
        StartDate: Date;
        EndDate: Date;
    begin
        StartDate := DMY2Date(1, 1, 2024);
        EndDate := DMY2Date(31, 12, 2024);

        CustomerRec.SetRange("No.", 'CUST001');
        CustomerRec.SetRange("Date Filter", StartDate, EndDate);

        if CustomerRec.FindFirst() then begin
            CustomerRec.CalcFields("Total Sales");
            Message('Total Sales for %1 from %2 to %3 is %4',
                    CustomerRec."Name", StartDate, EndDate, CustomerRec."Total Sales");
        end;
    end;

การสร้าง Procedure ที่ใช้ FlowFields และ FlowFilters

เราสามารถสร้างฟังก์ชันเพื่อคำนวณยอดขายของลูกค้าในช่วงวันที่ที่กำหนดได้

procedure GetTotalSales(CustomerNo: Code[20]; StartDate: Date; EndDate: Date): Decimal
var
    CustomerRec: Record Customer;
begin
    CustomerRec.SetRange("No.", CustomerNo);
    CustomerRec.SetRange("Date Filter", StartDate, EndDate);

    if CustomerRec.FindFirst() then begin
        CustomerRec.CalcFields("Total Sales");
        exit(CustomerRec."Total Sales");
    end else
        exit(0);
end;

การเรียกใช้ Procedure GetTotalSales

    var
        TotalSales: Decimal;
    begin
        TotalSales := GetTotalSales('CUST001', DMY2Date(1, 1, 2023), DMY2Date(31, 12, 2023));
        Message('Total Sales is %1', TotalSales);
    end;

สรุป

FlowFields และ FlowFilters เป็นเครื่องมือที่ทรงพลังใน AL สำหรับการคำนวณและกรองข้อมูลอย่างมีประสิทธิภาพ การเข้าใจการใช้งานและวิธีการทำงานของพวกมันจะช่วยให้การพัฒนาแอปพลิเคชันเป็นไปอย่างราบรื่นและมีประสิทธิภาพมากขึ้น

Dynamics 365 Business Central: การใช้งาน ConvertDateTimeFromUTCToTimeZone ใน TypeHelper Codeunit

ในการพัฒนาแอปพลิเคชันด้วยภาษา AL สำหรับ Microsoft Dynamics 365 Business Central การจัดการกับวันที่และเวลา (DateTime) เป็นสิ่งที่สำคัญ โดยเฉพาะอย่างยิ่งเมื่อมีการใช้งานในหลายเขตเวลา (Time Zones) ฟังก์ชัน ConvertDateTimeFromUTCToTimeZone ใน TypeHelper Codeunit ช่วยให้คุณสามารถแปลงค่า DateTime จาก UTC ไปยัง Time Zone ที่ต้องการได้อย่างง่ายดาย

รายละเอียดของฟังก์ชัน

รูปแบบของฟังก์ชัน

procedure ConvertDateTimeFromUTCToTimeZone(InputDateTime: DateTime; TimeZoneTxt: Text): DateTime
var
    TimeZoneInfo: DotNet TimeZoneInfo;
    Offset: Duration;
begin
    if TimeZoneTxt = '' then
        exit(InputDateTime);

    GetUserClientTypeOffset(Offset);
    InputDateTime := InputDateTime - Offset;

    TimeZoneInfo := TimeZoneInfo.FindSystemTimeZoneById(TimeZoneTxt);
    exit(InputDateTime + TimeZoneInfo.BaseUtcOffset);
end;

พารามิเตอร์

  • InputDateTime: ค่าวันที่และเวลาในรูปแบบ UTC ที่ต้องการแปลง
  • TimeZoneTxt: ชื่อของ Time Zone ที่ต้องการแปลงไป

คำอธิบาย

ฟังก์ชันนี้จะรับค่า DateTime ในรูปแบบ UTC และแปลงไปยัง Time Zone ที่ระบุโดย TimeZoneTxt ถ้า TimeZoneTxt ว่างเปล่า ฟังก์ชันจะคืนค่า InputDateTime โดยไม่ทำการแปลง

การทำงานภายในของฟังก์ชัน

  1. ตรวจสอบ TimeZoneTxt: ถ้า TimeZoneTxt เป็นค่าว่าง (''), ฟังก์ชันจะคืนค่า InputDateTime ทันที
  2. ปรับค่า Offset ของผู้ใช้: เรียกใช้ GetUserClientTypeOffset(Offset); เพื่อปรับค่าชดเชยของเวลาตามประเภทของ Client ที่ผู้ใช้กำลังใช้งาน
  3. แปลง TimeZoneTxt เป็น TimeZoneInfo: ใช้ TimeZoneInfo.FindSystemTimeZoneById(TimeZoneTxt); เพื่อหา Time Zone ที่ตรงกับชื่อที่ระบุ
  4. คำนวณเวลาที่แปลงแล้ว: นำค่า InputDateTime ลบด้วย Offset และบวกกับ TimeZoneInfo.BaseUtcOffset เพื่อให้ได้เวลาที่ถูกต้องใน Time Zone ที่ต้องการ

ตัวอย่างการใช้งาน

ตัวอย่างที่ 1: แปลงเวลาจาก UTC ไปยัง “Pacific Standard Time”

procedure TestConvertDateTime()
var
    TypeHelper: Codeunit "Type Helper";
    InputDateTime: DateTime;
    OutputDateTime: DateTime;
    TimeZoneTxt: Text;
begin
    InputDateTime := CURRENTDATETIME;
    TimeZoneTxt := 'Pacific Standard Time';

    OutputDateTime := TypeHelper.ConvertDateTimeFromUTCToTimeZone(InputDateTime, TimeZoneTxt);

    MESSAGE('เวลาปัจจุบันใน Pacific Standard Time คือ %1', FORMAT(OutputDateTime));
end;

คำอธิบายตัวอย่าง

  • กำหนด InputDateTime เป็นเวลาปัจจุบันใน UTC โดยใช้ CURRENTDATETIME
  • กำหนด TimeZoneTxt เป็น 'Pacific Standard Time'
  • เรียกใช้ฟังก์ชัน ConvertDateTimeFromUTCToTimeZone เพื่อแปลงเวลา
  • แสดงผลลัพธ์โดยใช้ MESSAGE

สรุป

ฟังก์ชัน ConvertDateTimeFromUTCToTimeZone ใน TypeHelper Codeunit เป็นเครื่องมือที่มีประโยชน์สำหรับการแปลงเวลาจาก UTC ไปยัง Time Zone ที่ต้องการ โดยรองรับการใช้งานกับ Time Zone ต่าง ๆ ที่ระบบปฏิบัติการรองรับ การเข้าใจการทำงานและการใช้งานฟังก์ชันนี้จะช่วยให้การพัฒนาแอปพลิเคชันด้วยภาษา AL มีประสิทธิภาพมากยิ่งขึ้น

Dynamics 365 Business Central: การใช้งาน Obsolete ใน AL Programming

ในภาษา AL ที่ใช้สำหรับการพัฒนา Microsoft Dynamics 365 Business Central เรามีคุณสมบัติที่เรียกว่า Obsolete ซึ่งใช้สำหรับการทำเครื่องหมาย (mark) ว่า object หรือ element ในโค้ดของเราไม่ควรถูกใช้งานอีกต่อไป เช่น table, field, หรือ procedure

ทำไมต้องใช้ Obsolete ?

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

  • แจ้งเตือนนักพัฒนาว่าส่วนนี้จะถูกเลิกใช้งาน
  • ป้องกันการใช้งาน object ที่ไม่ต้องการ
  • จัดการกับการปรับปรุงเวอร์ชันในอนาคตอย่างมีประสิทธิภาพ

การใช้งาน Obsolete

Obsolete Attribute ประกอบด้วยสอง property หลัก

  1. ObsoleteState: กำหนดสถานะของการเลิกใช้งาน ซึ่งมีค่าสองค่า:
    • Pending: แสดงคำเตือน (warning) เมื่อมีการใช้งาน
    • Removed: แสดงข้อผิดพลาด (error) เมื่อมีการใช้งาน
  2. ObsoleteReason: ข้อความที่อธิบายเหตุผลของการเลิกใช้งาน

รูปแบบการใช้งาน

ObsoleteState = Pending|Removed;
ObsoleteReason = 'เหตุผลในการเลิกใช้งาน';

ตัวอย่างการใช้งานใน Procedure

สมมติว่าเรามี procedure ที่ต้องการเลิกใช้งาน

procedure CalculateDiscount(amount: Decimal): Decimal
var
    discountRate: Decimal;
begin
    // การคำนวณส่วนลดแบบเก่า
    discountRate := 0.1;
    exit(amount * discountRate);
end;

เราสามารถทำให้ procedure นี้ obsolete ได้ดังนี้

[Obsolete('This method is obsolete. Use NewCalculateDiscount instead.', '24.0')]
procedure CalculateDiscount(amount: Decimal): Decimal
var
    discountRate: Decimal;
begin
    discountRate := 0.1;
    exit(amount * discountRate);
end;

ในตัวอย่างนี้

  • เราใช้ [Obsolete()] attribute เพื่อทำให้ procedure นี้ obsolete
  • ข้อความ 'This method is obsolete. Use NewCalculateDiscount instead.' จะปรากฏเมื่อมีการใช้งาน procedure นี้
  • '24.0' ระบุว่า procedure นี้จะถูกเลิกใช้งานในเวอร์ชัน 24.0

ตัวอย่างการใช้งานใน Field

ถ้าเรามี field ใน table ที่ต้องการเลิกใช้งาน

fields
{
    field(1000; "Old Field"; Text[50])
    {
        ObsoleteState = Removed;
        ObsoleteReason = 'This field is no longer used.';
    }
}

ในกรณีนี้

  • เมื่อ ObsoleteState ถูกตั้งเป็น Removed การใช้งาน field นี้จะทำให้เกิด error
  • ObsoleteReason ให้ข้อมูลเพิ่มเติมแก่นักพัฒนาเกี่ยวกับเหตุผลในการเลิกใช้งาน

การจัดการกับ Obsolete Object

เมื่อ object ถูกทำเครื่องหมายเป็น obsolete

  • หยุดการใช้งานในโค้ดใหม่
  • อัปเดตโค้ดเก่าที่เรียกใช้งาน object นั้น
  • เตรียมการสำหรับการลบ object นั้นในเวอร์ชันอนาคต

สรุป

การใช้ Obsolete ในภาษา AL เป็นวิธีที่มีประสิทธิภาพในการจัดการกับการเลิกใช้งาน object หรือ element ในโค้ดของเรา ช่วยให้นักพัฒนาสามารถรับรู้และปรับปรุงโค้ดตามการเปลี่ยนแปลงได้อย่างรวดเร็ว

Dynamics 365 Business Central: การใช้งาน TryFunction ใน AL Programming

ในภาษา AL ที่ใช้สำหรับการพัฒนา Extension สำหรับ Microsoft Dynamics 365 Business Central การจัดการข้อผิดพลาด (Error Handling) เป็นสิ่งสำคัญที่ช่วยให้ระบบทำงานได้อย่างมีประสิทธิภาพและเสถียร ในบทความนี้ เราจะมาอธิบายเกี่ยวกับ TryFunction Attribute ซึ่งเป็นเครื่องมือที่ช่วยในการจัดการข้อผิดพลาดในภาษา AL

TryFunction Attribute คืออะไร?

TryFunction Attribute เป็นการระบุให้กับ procedure หรือ function ในภาษา AL ว่าฟังก์ชันนั้นสามารถทดลองดำเนินการได้ โดยหากเกิดข้อผิดพลาดขึ้น ฟังก์ชันจะไม่ทำให้โปรแกรมหยุดทำงานด้วย runtime error แต่จะคืนค่าเป็น false แทน ซึ่งช่วยให้เราสามารถจัดการกับข้อผิดพลาดได้อย่างยืดหยุ่น

การใช้งาน TryFunction

การใช้ TryFunction ต้องระบุ [TryFunction] ไว้ก่อนการประกาศฟังก์ชัน ดังนี้

[TryFunction]
local procedure MyTryFunction()
begin
    // โค้ดที่อาจเกิดข้อผิดพลาด
end;

เมื่อเรียกใช้ฟังก์ชันนี้ เราสามารถตรวจสอบผลลัพธ์ได้ว่าการดำเนินการสำเร็จหรือไม่

procedure TestTryFunction()
var
    Success: Boolean;
begin
    Success := MyTryFunction();
    if not Success then
        Message('An error occurred during processing.');
end;

ตัวอย่างการใช้งาน

ตัวอย่างที่ 1: การแบ่งด้วยศูนย์

[TryFunction]
local procedure DivideNumbers(a: Integer; b: Integer)
var
    Result: Integer;
begin
    Result := a / b; // หาก b เป็น 0 จะเกิดข้อผิดพลาด
end;

procedure TestDivision()
var
    IsSuccess: Boolean;
begin
    IsSuccess := DivideNumbers(10, 0);
    if not IsSuccess then
        Message('Cannot divide by zero.');
end;

ตัวอย่างที่ 2: การ Insert ข้อมูลที่มี Key ซ้ำ

[TryFunction]
local procedure InsertCustomer(CustomerNo: Code[20])
var
    Customer: Record Customer;
begin
    Customer."No." := CustomerNo;
    Customer.Insert(); // หาก CustomerNo ซ้ำ จะเกิดข้อผิดพลาด
end;

procedure AddCustomer()
var
    IsSuccess: Boolean;
begin
    IsSuccess := InsertCustomer('C0001');
    if not IsSuccess then
        Message('Customer already exists.');
end;

ข้อควรระวังในการใช้ TryFunction

  • Transaction Scope: หาก TryFunction ถูกใช้ภายใน transaction การเปลี่ยนแปลงทั้งหมดจะถูกยกเลิก (rollback) หากเกิดข้อผิดพลาด
  • ไม่สามารถคืนค่าประเภทอื่นได้: ฟังก์ชันที่เป็น TryFunction ไม่สามารถมี return value ที่ไม่ใช่ Boolean
  • Performance Impact: การใช้ TryFunction อาจมีผลต่อประสิทธิภาพของระบบ เนื่องจากการจัดการข้อผิดพลาดต้องใช้ทรัพยากรเพิ่มเติม

สรุป

TryFunction Attribute เป็นเครื่องมือที่มีประโยชน์ในการจัดการข้อผิดพลาดในภาษา AL ช่วยให้โปรแกรมไม่หยุดทำงานเมื่อเกิดข้อผิดพลาด แต่สามารถตรวจสอบและจัดการได้ตามต้องการ อย่างไรก็ตาม ควรใช้งานอย่างระมัดระวังและเข้าใจถึงข้อจำกัดต่าง ๆ เพื่อให้ระบบทำงานได้อย่างมีประสิทธิภาพ

Dynamics 365 Business Central: การใช้งาน Isolated Event ใน AL Programming

ในภาษา AL ที่ใช้สำหรับการพัฒนา Extension ใน Microsoft Dynamics 365 Business Central มีความสามารถใหม่ที่เรียกว่า Isolated Events ซึ่งช่วยให้การจัดการกับข้อผิดพลาด (Error Handling) ใน Event Subscriber มีประสิทธิภาพมากขึ้น บทความนี้จะอธิบายรายละเอียดเกี่ยวกับ Isolated Events พร้อมตัวอย่างการใช้งาน และแสดงวิธีการประกาศ Procedure ที่เกี่ยวข้อง

Isolated Events คืออะไร?

Isolated Events เป็นคุณสมบัติที่ช่วยให้ Event Subscribers สามารถทำงานอย่างเป็นอิสระ (Isolated) จากกัน เมื่อเกิดข้อผิดพลาดใน Subscriber หนึ่ง จะไม่ส่งผลกระทบต่อการทำงานของ Subscribers อื่นๆ หรือการทำงานของโปรแกรมหลัก (Main Code)

ทำไมต้องใช้ Isolated Events?

  • ความเสถียรของระบบ: เมื่อมีข้อผิดพลาดเกิดขึ้นใน Subscriber หนึ่ง โปรแกรมหลักยังคงทำงานต่อไปได้
  • การควบคุมข้อผิดพลาด: ช่วยให้สามารถจัดการกับข้อผิดพลาดในระดับของ Subscriber ได้โดยไม่กระทบกับการทำงานอื่น
  • การย้อนกลับการเปลี่ยนแปลง: ถ้า Subscriber ทำการเปลี่ยนแปลงข้อมูลในฐานข้อมูลและเกิดข้อผิดพลาด การเปลี่ยนแปลงนั้นจะถูกยกเลิก (Rolled Back)

การประกาศ Isolated Events

การประกาศ Isolated Event ใน AL ทำได้โดยการใช้ Attribute [InternalEvent(false, true)] โดยมีรูปแบบดังนี้

[InternalEvent(false, true)]
local procedure MyIsolatedEvent(Parameters)
begin
    // Event Logic
end;
  • IncludeSender (พารามิเตอร์ตัวแรก)
  • Isolated (พารามิเตอร์ตัวที่สอง, Optional)

ตัวอย่างการใช้งาน Isolated Events

codeunit 50100 SimpleIsolatedEventSample
{
    trigger OnRun()
    var
        MessageText: Text[100];
    begin
        MessageText := 'เริ่มต้น';

        MyIsolatedEvent(MessageText);

        Message('ข้อความสุดท้าย: %1', MessageText);
    end;

    [InternalEvent(false, true)]
    local procedure MyIsolatedEvent(var MessageText: Text[100])
    begin
        // เหตุการณ์นี้จะมีผู้ติดตามเหตุการณ์สองตัว
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::SimpleIsolatedEventSample, 'MyIsolatedEvent', '', false, false)]
    local procedure FailingSubscriber(var MessageText: Text[100])
    begin
        MessageText := MessageText + ' | จาก FailingSubscriber';
        Error('เกิดข้อผิดพลาดใน FailingSubscriber');
        // โค้ดด้านล่างนี้จะไม่ถูกเรียกใช้เนื่องจากเกิดข้อผิดพลาด
        MessageText := MessageText + ' | หลังจากข้อผิดพลาด';
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::SimpleIsolatedEventSample, 'MyIsolatedEvent', '', false, false)]
    local procedure SuccessfulSubscriber(var MessageText: Text[100])
    begin
        MessageText := MessageText + ' | จาก SuccessfulSubscriber';
    end;
}

การอธิบาย Source Code

1. ส่วนของ OnRun()

trigger OnRun()
var
    MessageText: Text[100];
begin
    MessageText := 'เริ่มต้น';

    MyIsolatedEvent(MessageText);

    Message('ข้อความสุดท้าย: %1', MessageText);
end;
  • กำหนดค่าเริ่มต้นให้กับ MessageText เป็น 'เริ่มต้น'
  • เรียกใช้ MyIsolatedEvent(MessageText); ซึ่งเป็น Isolated Event
  • แสดงผลข้อความสุดท้ายของ MessageText ด้วย Message()

2. การประกาศ Isolated Event MyIsolatedEvent

[InternalEvent(false, true)]
local procedure MyIsolatedEvent(var MessageText: Text[100])
begin
    // เหตุการณ์นี้จะมีผู้ติดตามเหตุการณ์สองตัว
end;
  • ใช้ Attribute [InternalEvent(false, true)] เพื่อกำหนดให้เป็น Isolated Event
  • รับ Parameter เป็น var MessageText: Text[100] เพื่อให้ Subscribers สามารถแก้ไขค่าได้

3. Subscriber ที่เกิดข้อผิดพลาด FailingSubscriber

[EventSubscriber(ObjectType::Codeunit, Codeunit::SimpleIsolatedEventSample, 'MyIsolatedEvent', '', false, false)]
local procedure FailingSubscriber(var MessageText: Text[100])
begin
    MessageText := MessageText + ' | จาก FailingSubscriber';
    Error('เกิดข้อผิดพลาดใน FailingSubscriber');
    // โค้ดด้านล่างนี้จะไม่ถูกเรียกใช้เนื่องจากเกิดข้อผิดพลาด
    MessageText := MessageText + ' | หลังจากข้อผิดพลาด';
end;
  • เพิ่มข้อความ ' | จาก FailingSubscriber' ต่อท้าย MessageText
  • ทำให้เกิดข้อผิดพลาดด้วย Error('เกิดข้อผิดพลาดใน FailingSubscriber');
  • โค้ดหลังจาก Error() จะไม่ถูกดำเนินการ

4. Subscriber ที่ทำงานสำเร็จ SuccessfulSubscriber

[EventSubscriber(ObjectType::Codeunit, Codeunit::SimpleIsolatedEventSample, 'MyIsolatedEvent', '', false, false)]
local procedure SuccessfulSubscriber(var MessageText: Text[100])
begin
    MessageText := MessageText + ' | จาก SuccessfulSubscriber';
end;
  • เพิ่มข้อความ ' | จาก SuccessfulSubscriber' ต่อท้าย MessageText

การทำงานของโปรแกรม

1. เมื่อ OnRun() ถูกเรียกใช้ MessageText จะถูกตั้งค่าเป็น 'เริ่มต้น'
2. เรียกใช้ MyIsolatedEvent(MessageText); ซึ่งมี Subscribers สองตัว
3. การเรียกใช้ Subscribers:
- FailingSubscriber:
- เพิ่มข้อความ ' | จาก FailingSubscriber' ใน MessageText
- ทำให้เกิดข้อผิดพลาดด้วย Error()
- การเปลี่ยนแปลงใน MessageText จะยังคงอยู่
- SuccessfulSubscriber:
- เพิ่มข้อความ ' | จาก SuccessfulSubscriber' ใน MessageText
4. กลับมาที่ OnRun() และแสดงผล MessageText

ผลลัพธ์ที่แสดง

ข้อความสุดท้าย: เริ่มต้น | จาก FailingSubscriber | จาก SuccessfulSubscriber

การวิเคราะห์

  • Isolated Event ช่วยให้ข้อผิดพลาดใน FailingSubscriber ไม่หยุดการทำงานของโปรแกรมหลัก
  • การเปลี่ยนแปลงในตัวแปร MessageText ภายใน Subscribers จะยังคงอยู่ แม้ว่าเกิดข้อผิดพลาด
  • Subscribers ที่เหลือ (SuccessfulSubscriber) ยังคงถูกเรียกใช้ตามปกติ

การจัดการกับการเปลี่ยนแปลงในฐานข้อมูล

หากมีการเปลี่ยนแปลงฐานข้อมูลใน Subscriber ที่เกิดข้อผิดพลาด การเปลี่ยนแปลงนั้นจะถูกยกเลิก

ตัวอย่างเพิ่มเติม

[EventSubscriber(ObjectType::Codeunit, Codeunit::SimpleIsolatedEventSample, 'MyIsolatedEvent', '', false, false)]
local procedure DatabaseChangingSubscriber()
var
    Customer: Record Customer;
begin
    Customer.DeleteAll(); // พยายามลบข้อมูลลูกค้าทั้งหมด
    Error('เกิดข้อผิดพลาดหลังจากลบลูกค้า');
end;
  • เมื่อเกิดข้อผิดพลาด การลบข้อมูลในตาราง Customer จะถูกยกเลิก
  • ข้อมูลในฐานข้อมูลจะไม่ถูกเปลี่ยนแปลง

สรุป

  • Isolated Events ช่วยให้การจัดการข้อผิดพลาดใน Event Subscribers มีประสิทธิภาพมากขึ้น
  • ข้อผิดพลาดใน Subscriber จะไม่หยุดการทำงานของโปรแกรมหลักหรือ Subscribers อื่น
  • การเปลี่ยนแปลงในตัวแปรภายใน Subscribers จะยังคงอยู่ แม้ว่าเกิดข้อผิดพลาด
  • การเปลี่ยนแปลงในฐานข้อมูลจะถูกยกเลิกหาก Subscriber นั้นเกิดข้อผิดพลาด
  • การประกาศ Isolated Event ใช้ [InternalEvent(false, true)]

ข้อควรระวังและคำแนะนำ

  • ควรใช้ Isolated Events เมื่อจำเป็นต้องให้โปรแกรมหลักทำงานต่อเนื่อง แม้ว่าจะมีข้อผิดพลาดใน Subscribers
  • การจัดการข้อผิดพลาดใน Subscribers ควรทำอย่างรอบคอบ เพื่อป้องกันผลกระทบที่ไม่คาดคิด
  • ควรตรวจสอบและทดสอบการทำงานของ Subscribers อย่างละเอียด

Dynamics 365 Business Central: แนวทางการตั้งชื่อ Object และ Field ด้วย Prefix ใน AL Programming

ใน AL Programming ซึ่งเป็นภาษาสำหรับพัฒนาโซลูชันใน Dynamics 365 Business Central การใช้ Prefix ใน Object และ Field เป็นเทคนิคสำคัญที่ช่วยให้เราสามารถจัดการโค้ดได้ง่ายขึ้นและป้องกันปัญหาการชนกันของชื่อระหว่าง Object หรือ Field ที่อาจซ้ำกันได้ ในบทความนี้ เราจะมาดูความสำคัญและการใช้ Prefix ทั้งใน Object และ Field พร้อมด้วยตัวอย่างการใช้งานแบบละเอียด เพื่อช่วยให้คุณเข้าใจและสามารถนำไปประยุกต์ใช้ในการพัฒนาโค้ดของคุณได้

ความสำคัญของการใช้ Prefix

Prefix คือตัวอักษรที่เรานำหน้าชื่อ Object หรือ Field เพื่อระบุถึงความเป็นส่วนหนึ่งของโซลูชันใด ๆ โดยเฉพาะ รวมถึงการป้องกันการชนกันของชื่อระหว่างโค้ดที่สร้างขึ้นเองและโค้ดที่มาจากระบบมาตรฐาน ซึ่งช่วยให้โค้ดดูมีโครงสร้างและเข้าใจง่ายขึ้น โดย Prefix ควรจะเป็นคำย่อที่สื่อความหมายหรือระบุถึงฟังก์ชันของ Object หรือ Field นั้น ๆ อย่างชัดเจน

ตัวอย่าง Prefix

  • ชื่อบริษัท เช่น MCS สำหรับ MyCompanySolution
  • ชื่อโมดูล เช่น HR สำหรับโมดูลทรัพยากรบุคคล

การใช้ Prefix ใน Object

การใช้ Prefix กับ Object เช่น Codeunit, Table, Page, Report หรือ Query เป็นวิธีที่ดีในการทำให้ Object ต่าง ๆ ในโซลูชันของเรามีความแตกต่างจาก Object ในระบบมาตรฐาน และสามารถค้นหาและจัดการได้ง่ายขึ้น โดย Prefix จะช่วยให้เราสามารถจัดการกับ Object ที่เกี่ยวข้องได้อย่างมีระเบียบ

ตัวอย่าง: การใช้ Prefix ใน Codeunit

codeunit 50100 MCS_CustomerManagement
{
    procedure ManageCustomer(CustomerNo: Code[20])
    var
        CustomerRec: Record Customer;
    begin
        if CustomerRec.Get(CustomerNo) then
            Message('Managing customer: %1', CustomerRec.Name)
        else
            Error('Customer %1 not found', CustomerNo);
    end;
}

ในตัวอย่างนี้ Codeunit MCS_CustomerManagement ถูกตั้งชื่อด้วย Prefix MCS ซึ่งหมายถึงว่าเป็นส่วนหนึ่งของโซลูชัน MyCompanySolution ซึ่งจะทำให้เราแยกแยะได้ง่ายเมื่อโซลูชันมีการเพิ่ม Object มากขึ้นเรื่อย ๆ

การใช้ Prefix ใน Field

นอกจาก Object แล้ว การใช้ Prefix ใน Field ก็มีความสำคัญไม่น้อย เช่น ในกรณีที่เราต้องการเพิ่ม Field ใหม่ลงใน Table ที่มีอยู่แล้ว เช่น Customer การใช้ Prefix จะช่วยให้เราสามารถระบุได้ว่า Field ใดเป็นส่วนหนึ่งของโซลูชันของเรา และป้องกันการชนกันกับ Field อื่นที่อาจถูกเพิ่มจากโซลูชันอื่น

ตัวอย่าง: การใช้ Prefix ใน Field ของ Table

tableextension 50100 MCS_CustomerExtension extends Customer
{
    fields
    {
        field(50000; MCS_AdditionalInfo; Text[250])
        {
            Caption = 'Additional Info';
            DataClassification = ToBeClassified;
        }
    }
}

ในตัวอย่างนี้ เราได้สร้าง Field ใหม่ใน Table Customer ชื่อว่า MCS_AdditionalInfo ซึ่ง Prefix MCS ทำให้เราทราบได้ว่า Field นี้เป็นส่วนหนึ่งของโซลูชันของเราและไม่ใช่ Field ที่มาจากระบบมาตรฐาน

แนวทางปฏิบัติที่ดีสำหรับการใช้ Prefix

  1. สั้นและสื่อความหมาย: Prefix ควรเป็นตัวอักษรสั้น ๆ ที่สื่อความหมายถึงโซลูชันหรือโมดูลนั้น ๆ เช่น ตัวอักษรย่อของชื่อบริษัทหรือชื่อโครงการ
  2. ใช้ Prefix อย่างสม่ำเสมอ: ใช้ Prefix เดียวกันใน Object และ Field ที่เกี่ยวข้องกันทั้งหมดในโซลูชันเพื่อให้โค้ดของคุณดูเป็นระเบียบ
  3. ป้องกันการชนกันของชื่อ: การใช้ Prefix จะช่วยลดความเสี่ยงของการชนกันของชื่อระหว่างโซลูชันต่าง ๆ โดยเฉพาะอย่างยิ่งเมื่อมีการรวมโซลูชันหลายตัวใน Business Central

ตัวอย่างการใช้งาน Prefix ทั้งใน Object และ Field

ต่อไปนี้เป็นตัวอย่างของการใช้ Prefix ในหลาย ๆ Object รวมทั้งใน Field เพื่อแสดงถึงการจัดการโซลูชันที่เป็นระบบและชัดเจน

การใช้ Prefix ใน Page และ Field

pageextension 50100 MCS_CustomerCard extends "Customer Card"
{
    layout
    {
        addlast(Content)
        {
            group(MCS_Group)
            {
                field(MCS_AdditionalInfo; Rec.MCS_AdditionalInfo)
                {
                    ApplicationArea = All;
                }
            }
        }
    }
}

ในตัวอย่างนี้เราได้สร้าง Page ที่ขยายจาก “Customer Card” และเพิ่ม Field ที่มี Prefix MCS เพื่อให้ชัดเจนว่า Field นั้นเป็นของโซลูชัน MyCompanySolution และเราสามารถแยกได้ว่ามาจากส่วนไหนของระบบ

สรุป

การใช้ Prefix ใน Object และ Field ใน AL Programming เป็นเทคนิคที่สำคัญในการพัฒนาโค้ดใน Dynamics 365 Business Central เพราะช่วยให้การจัดการโค้ดเป็นระเบียบ ป้องกันการชนกันของชื่อ และเพิ่มความสะดวกในการค้นหาและแก้ไขโค้ดในอนาคต การใช้ Prefix ที่สื่อความหมายและสม่ำเสมอจะช่วยให้โซลูชันของคุณดูมืออาชีพและใช้งานได้อย่างมีประสิทธิภาพ

Dynamics 365 Business Central: การใช้งาน OutStream และ InStream ใน AL Programming

ในการพัฒนา Dynamics 365 Business Central ด้วยภาษา AL (Application Language) การจัดการข้อมูลแบบสตรีม (Stream) เป็นสิ่งสำคัญ โดยเฉพาะเมื่อเราต้องการอ่านหรือเขียนข้อมูลที่มีขนาดใหญ่หรือไม่กำหนดขนาดแน่นอน เช่น ข้อมูลประเภท Blob, ไฟล์, หรือข้อความที่ยาวมากๆ

บทความนี้จะอธิบายรายละเอียดเกี่ยวกับ OutStream และ InStream พร้อมตัวอย่างการใช้งานและรูปแบบการเขียนโปรแกรม

การสร้างฟิลด์ Blob: “Body Response”

field(1; "Body Response"; Blob)
{
    DataClassification = ToBeClassified;
}

คำอธิบาย

  • Field ID (1): หมายเลขของฟิลด์ในตาราง
  • ชื่อฟิลด์ (“Body Response”): ชื่อของฟิลด์ที่ใช้ในการอ้างอิง
  • ประเภทฟิลด์ (Blob): ประเภทข้อมูล Blob ใช้สำหรับเก็บข้อมูลไบนารีหรือข้อมูลที่มีขนาดใหญ่ เช่น ไฟล์, รูปภาพ, หรือข้อความที่ยาวมาก
  • DataClassification: กำหนดการจัดประเภทข้อมูลเพื่อความปลอดภัยและการปฏิบัติตามกฎระเบียบ

การใช้งานร่วมกับ InStream และ OutStream

ฟิลด์ "Body Response" ที่เป็นประเภท Blob ทำหน้าที่เป็นที่เก็บข้อมูลหลักสำหรับการอ่านและเขียนผ่าน InStream และ OutStream ดังนี้:

  • การเขียนข้อมูลลงใน Blob: ใช้ OutStream เพื่อเขียนข้อมูลลงในฟิลด์ Blob
  • การอ่านข้อมูลจาก Blob: ใช้ InStream เพื่ออ่านข้อมูลจากฟิลด์ Blob

OutStream

OutStream เป็น DataType ที่ใช้สำหรับการเขียนข้อมูลลงในสตรีม เมื่อคุณต้องการส่งออกข้อมูลหรือบันทึกข้อมูลลงใน Blob, ไฟล์, หรือสตรีมอื่นๆ คุณจะใช้ OutStream

วิธีการใช้งาน OutStream

  • การสร้าง OutStream: ใช้เมธอด CreateOutStream เพื่อสร้าง OutStream จากตัวแปรหรือฟิลด์ที่รองรับ เช่น Blob, File, หรือ MemoryStream
  • การเขียนข้อมูล: ใช้เมธอดต่างๆ ของ OutStream เช่น WriteText, Write เพื่อเขียนข้อมูลลงในสตรีม

ตัวอย่าง SetResponseText

procedure SetResponseText(pText: Text)
var
    OutStream: OutStream;
begin
    Clear("Body Response");
    "Body Response".CreateOutStream(OutStream, TEXTENCODING::UTF8);
    OutStream.WriteText(Format(pText));
end;

คำอธิบาย

  • Clear("Body Response"); เคลียร์ค่าในฟิลด์ “Body Response” เพื่อเริ่มต้นใหม่
  • "Body Response".CreateOutStream(OutStream, TEXTENCODING::UTF8); สร้าง OutStream จากฟิลด์ “Body Response” โดยกำหนดการเข้ารหัสเป็น UTF8
  • OutStream.WriteText(Format(pText)); เขียนข้อความที่ถูกฟอร์แมตแล้วลงใน OutStream

InStream

InStream เป็น DataType ที่ใช้สำหรับการอ่านข้อมูลจากสตรีม เมื่อคุณต้องการนำเข้าข้อมูลหรืออ่านข้อมูลจาก Blob, ไฟล์, หรือสตรีมอื่นๆ คุณจะใช้ InStream

วิธีการใช้งาน InStream

  • การสร้าง InStream: ใช้เมธอด CreateInStream เพื่อสร้าง InStream จากตัวแปรหรือฟิลด์ที่รองรับ
  • การอ่านข้อมูล: ใช้เมธอดต่างๆ ของ InStream เช่น ReadText, Read เพื่ออ่านข้อมูลจากสตรีม

ตัวอย่าง GetResponseText

procedure GetResponseText(): Text
var
    InStream: InStream;
    ResultText: Text;
begin
    CalcFields("Body Response");
    "Body Response".CreateInStream(InStream, TextEncoding::UTF8);
    InStream.ReadText(ResultText);
    exit(ResultText);
end;

คำอธิบาย

  • CalcFields("Body Response"); คำนวณฟิลด์ “Body Response” เพื่อให้แน่ใจว่าข้อมูลพร้อมสำหรับการอ่าน
  • "Body Response".CreateInStream(InStream, TextEncoding::UTF8); สร้าง InStream จากฟิลด์ “Body Response” โดยกำหนดการเข้ารหัสเป็น UTF8
  • InStream.ReadText(ResultText); อ่านข้อความจาก InStream และเก็บไว้ในตัวแปร ResultText
  • exit(ResultText); ส่งคืนข้อความที่อ่านได้

สรุป

การใช้ OutStream และ InStream กับฟิลด์ Blob ช่วยให้สามารถจัดการข้อมูลขนาดใหญ่ได้อย่างมีประสิทธิภาพ โดย OutStream ใช้สำหรับเขียนข้อมูลลงใน Blob และ InStream ใช้สำหรับอ่านข้อมูลจาก Blob เหมาะสำหรับการจัดเก็บและเรียกคืนข้อความหรือไฟล์ใน AL Programming

เคล็ดลับ

  • ควรกำหนด TextEncoding เมื่อสร้างสตรีมเพื่อป้องกันปัญหาการเข้ารหัสของข้อความ
  • อย่าลืมใช้ CalcFields เมื่ออ่านข้อมูลจากฟิลด์ที่เป็น FlowField หรือ Blob

Dynamics 365 Business Central: การใช้งาน TestField ใน AL Programming

TestField เป็นฟังก์ชันที่ใช้ในการตรวจสอบค่าของฟิลด์ใน AL Programming ว่ามีค่าตามที่กำหนดไว้หรือไม่ ซึ่งหากฟิลด์นั้นไม่มีค่าตามที่คาดหวังจะทำให้เกิด Error ขึ้น ฟังก์ชันนี้มีประโยชน์มากในการรักษาความถูกต้องของข้อมูลและป้องกันไม่ให้เกิดข้อผิดพลาดในการประมวลผลในภายหลัง

การใช้งานพื้นฐาน

TestField ใช้เพื่อตรวจสอบค่าฟิลด์ที่เราคาดหวังว่าควรจะมีค่าอยู่เสมอ หากฟิลด์นั้นว่างเปล่าหรือไม่ตรงกับค่าเฉพาะที่เรากำหนดไว้ จะเกิด Error เพื่อบอกให้ผู้ใช้งานแก้ไขข้อมูล

procedure ValidateCustomerNo(CustomerRecord: Record Customer)
begin
    CustomerRecord.TestField("No."); // ตรวจสอบว่าฟิลด์ "No." ของลูกค้าไม่ว่างเปล่า
end;

ในตัวอย่างนี้ ฟังก์ชัน TestField ใช้ตรวจสอบว่า Customer No. ไม่ว่างเปล่า ซึ่งถ้าไม่มีค่า จะเกิดข้อผิดพลาดทันที

การใช้งานพร้อมเงื่อนไขค่าเฉพาะ

นอกจากการตรวจสอบว่าฟิลด์ไม่ว่างเปล่าแล้ว TestField ยังสามารถใช้ตรวจสอบว่าฟิลด์มีค่าตรงกับที่กำหนดหรือไม่

procedure CheckOrderStatus(SalesOrder: Record "Sales Header")
begin
    SalesOrder.TestField(Status, SalesOrder.Status::Open); // ตรวจสอบว่าสถานะของ Sales Order ต้องเป็น "Open"
end;

ตัวอย่างนี้จะตรวจสอบว่าสถานะของ Sales Order ต้องเป็น ‘Open’ เท่านั้น ถ้าไม่ใช่ จะเกิด Error ขึ้น

การใช้งานกับฟิลด์หลายประเภท (Complex Example)

การตรวจสอบฟิลด์หลายประเภท เช่น Integer, Boolean, และ Date

procedure ValidateSalesLine(SalesLine: Record "Sales Line")
begin
    // ตรวจสอบว่า Quantity ต้องไม่เป็นค่าว่างหรือเป็น 0
    SalesLine.TestField(Quantity, 1); 
    
    // ตรวจสอบว่า Boolean field ต้องเป็น TRUE
    SalesLine.TestField("Line Discount", false); 
    
    // ตรวจสอบว่า Date ต้องมีค่า
    SalesLine.TestField("Shipment Date");
end;

ในตัวอย่างนี้ เราตรวจสอบฟิลด์หลากหลายประเภท ทั้ง Integer, Boolean, และ Date เพื่อให้แน่ใจว่าค่าที่เก็บในแต่ละฟิลด์ถูกต้องและไม่ว่างเปล่า

ประโยชน์ของการใช้ TestField

  1. ความปลอดภัยของข้อมูล (Data Integrity): การใช้ TestField ช่วยให้มั่นใจว่าข้อมูลที่ใช้ในกระบวนการต่าง ๆ จะมีค่าที่ถูกต้องก่อนที่จะดำเนินการใด ๆ
  2. การป้องกันข้อผิดพลาด (Error Prevention): หากมีการใช้ TestField ในการตรวจสอบค่าต่าง ๆ ก่อนที่จะดำเนินการ ระบบจะสามารถหยุดการประมวลผลได้หากค่าที่ตรวจสอบไม่ถูกต้อง ซึ่งช่วยลดข้อผิดพลาดที่อาจเกิดขึ้นในระบบ
  3. ช่วยในการ Debugging: เมื่อเกิด Error จากการใช้ TestField ระบบจะแจ้งเตือนว่าฟิลด์ใดไม่ผ่านการตรวจสอบ ทำให้ง่ายต่อการค้นหาสาเหตุของปัญหา

สรุป

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

Dynamics 365 Business Central: การใช้งานฟังก์ชัน GetField, GetFieldLengthใน AL Programming

ในบทความนี้ เราจะมาทำความเข้าใจและอธิบายการใช้งานฟังก์ชันสำคัญสามตัวใน Type Helper Codeunit ซึ่งถูกใช้งานใน AL Programming ของ Dynamics 365 Business Central โดยฟังก์ชันทั้งสามที่เราจะกล่าวถึงคือ GetField และ GetFieldLength ซึ่งมีประโยชน์ในการจัดการกับข้อมูลใน Table โดยเฉพาะอย่างยิ่งการจัดการ Field ที่อาจถูกลบ (Obsolete) หรือมีข้อกำหนดพิเศษ

1. การใช้ฟังก์ชัน GetField

ฟังก์ชัน GetField ถูกออกแบบมาให้สามารถดึง Field จาก Table ที่ต้องการโดยใช้หมายเลขของ Table และ Field นอกจากนี้ยังมีการตรวจสอบว่าสถานะของ Field นั้นไม่ถูกลบ (Obsolete)

procedure GetField(TableNo: Integer; FieldNo: Integer; var "Field": Record "Field") Result: Boolean
var
    IsHandled: Boolean;
begin
    IsHandled := false;
    OnBeforeGetField(TableNo, FieldNo, "Field", Result, IsHandled);
    if IsHandled then
        exit(Result);

    exit(Field.Get(TableNo, FieldNo) and (Field.ObsoleteState <> Field.ObsoleteState::Removed));
end;

การทำงาน

  • รับค่า TableNo และ FieldNo เป็นหมายเลข Table และ Field ที่ต้องการค้นหา
  • ทำการเรียก Field จาก Table นั้น หากพบว่ามีการลบ Field (ObsoleteState::Removed) ฟังก์ชันจะส่งค่ากลับเป็น false
  • หาก Field นั้นยังคงใช้งานได้ จะส่งค่ากลับเป็น true

ตัวอย่างการใช้งาน GetField

procedure ValidateFieldInTable(TableNo: Integer; FieldNo: Integer)
var
    FieldRec: Record "Field";
    IsFieldValid: Boolean;
begin
    // เรียกฟังก์ชัน GetField เพื่อตรวจสอบว่าฟิลด์ที่ต้องการมีอยู่ในตารางหรือไม่
    IsFieldValid := TypeHelper.GetField(TableNo, FieldNo, FieldRec);
    
    // หากฟิลด์มีอยู่และไม่ถูกลบ จะทำการแสดงข้อความว่า Field ถูกต้อง
    if IsFieldValid then
        Message('Field %1 from table %2 is valid.', FieldRec."Field Caption", FieldRec.TableName)
    else
        // หากฟิลด์ถูกลบ หรือไม่พบฟิลด์ จะแสดงข้อความแจ้งเตือน
        Message('Field is obsolete or does not exist.');
end;

คำอธิบาย

  • ฟังก์ชัน ValidateFieldInTable ถูกใช้เพื่อตรวจสอบว่า Field ที่ต้องการมีอยู่ใน Table หรือไม่ โดยเรียกใช้ฟังก์ชัน GetField
  • หาก Field นั้นมีอยู่และไม่ถูกลบ (Obsolete) ฟังก์ชันจะทำการแสดงข้อความยืนยันว่าฟิลด์ยังสามารถใช้งานได้
  • หาก Field ถูกลบหรือไม่พบ จะทำการแสดงข้อความว่า Field นี้ไม่สามารถใช้งานได้หรือถูกลบแล้ว

2. การใช้ฟังก์ชัน GetFieldLength

ฟังก์ชัน GetFieldLength ใช้ในการดึงความยาวของ Field ที่ต้องการ โดยฟังก์ชันนี้จะเรียกใช้ GetField เพื่อดึงข้อมูล Field ก่อน แล้วจึงคืนค่าความยาวของ Field นั้นกลับมา

procedure GetFieldLength(TableNo: Integer; FieldNo: Integer) FieldLength: Integer
var
    "Field": Record "Field";
    IsHandled: Boolean;
begin
    IsHandled := false;
    OnBeforeGetFieldLength(Field, FieldLength, IsHandled);
    if IsHandled then
        exit(FieldLength);

    if GetField(TableNo, FieldNo, Field) then
        exit(Field.Len);

    exit(0);
end;

การทำงาน

  • เริ่มจากการเรียก GetField เพื่อตรวจสอบว่า Field ที่ต้องการมีอยู่หรือไม่
  • หาก Field มีอยู่ ฟังก์ชันจะคืนค่าความยาวของ Field (Field.Len)
  • หาก Field ไม่อยู่ จะคืนค่าเป็น 0

ตัวอย่างการใช้งาน GetFieldLength

procedure DisplayFieldLength(TableNo: Integer; FieldNo: Integer)
var
    FieldLength: Integer;
begin
    // เรียกใช้ GetFieldLength เพื่อตรวจสอบความยาวของ Field ที่ระบุ
    FieldLength := TypeHelper.GetFieldLength(TableNo, FieldNo);
    
    // หาก FieldLength มีค่ามากกว่า 0 จะแสดงความยาวของ Field
    if FieldLength > 0 then
        Message('The length of the field is %1.', FieldLength)
    else
        // หากไม่พบ Field หรือ Field ถูกลบออก จะแสดงข้อความแจ้งเตือน
        Message('Field does not exist or is obsolete.');
end;

คำอธิบาย

  • ฟังก์ชัน DisplayFieldLength ใช้ในการดึงความยาวของ Field ที่ระบุด้วยหมายเลข Table และ Field
  • หากฟิลด์มีอยู่ ฟังก์ชันจะส่งค่าความยาวของฟิลด์นั้นกลับมา
  • หากฟิลด์ไม่ถูกพบหรือถูกลบ (Obsolete) จะคืนค่าเป็น 0 และแสดงข้อความแจ้งเตือนว่า Field ไม่สามารถใช้งานได้

สรุป

ฟังก์ชัน GetField และ GetFieldLength เป็นฟังก์ชันที่สำคัญในการจัดการกับ Fields ใน Table โดยเฉพาะเมื่อเราต้องการตรวจสอบว่า Field นั้น ๆ ถูกลบหรือไม่ หรือเพื่อดึงข้อมูลของ Field มาใช้งานต่อ ฟังก์ชันเหล่านี้จะช่วยให้การจัดการข้อมูลใน AL Programming มีประสิทธิภาพมากยิ่งขึ้น