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 มีประสิทธิภาพมากยิ่งขึ้น

Dynamics 365 Business Central: การใช้ HtmlEncode, HtmlDecode, UrlEncode, และ UrlDecode ใน AL Programming

ใน AL Programming เราสามารถใช้ Type Helper Codeunit เพื่อจัดการกับการเข้ารหัสและถอดรหัสข้อมูล HTML และ URL ได้โดยใช้ฟังก์ชัน HtmlEncode, HtmlDecode, UrlEncode และ UrlDecode ซึ่งสำคัญในการป้องกันข้อมูลไม่ให้เกิดปัญหากับการแสดงผลใน HTML หรือการส่งข้อมูลผ่าน URL ที่มีอักขระพิเศษ

1. HtmlEncode และ HtmlDecode

  • HtmlEncode: ใช้ในการเข้ารหัสข้อมูลเพื่อให้แน่ใจว่าตัวอักษรพิเศษ เช่น <, >, &, และเครื่องหมายคำพูด (") ที่อาจเป็นสัญลักษณ์ใน HTML จะถูกแทนที่ด้วยโค้ดที่ถูกต้องเพื่อไม่ให้เกิดปัญหาหรือความขัดแย้งเมื่อแสดงผลในหน้าเว็บ เช่น:
    • < จะถูกเข้ารหัสเป็น &lt;
    • > จะถูกเข้ารหัสเป็น &gt;
  • HtmlDecode: ทำงานตรงกันข้ามกับ HtmlEncode คือถอดรหัสอักขระพิเศษที่ถูกเข้ารหัสกลับไปเป็นอักขระปกติ เพื่อให้สามารถแสดงข้อมูลที่แท้จริงได้

ตัวอย่างการใช้งาน HtmlEncode และ HtmlDecode ใน AL

procedure HtmlEncodeExample()
var
    InputText: Text;
    EncodedText: Text;
    DecodedText: Text;
begin
    // ข้อมูลที่มีอักขระพิเศษ
    InputText := '<div>สวัสดี & ยินดีต้อนรับ!</div>';
    
    // เข้ารหัส HTML
    EncodedText := TypeHelper.HtmlEncode(InputText);
    Message('Encoded HTML: %1', EncodedText); // จะแสดง: &lt;div&gt;สวัสดี &amp; ยินดีต้อนรับ!&lt;/div&gt;
    
    // ถอดรหัส HTML
    DecodedText := TypeHelper.HtmlDecode(EncodedText);
    Message('Decoded HTML: %1', DecodedText); // จะแสดง: <div>สวัสดี & ยินดีต้อนรับ!</div>
end;

2. UrlEncode และ UrlDecode

  • UrlEncode: ใช้สำหรับเข้ารหัส URL ซึ่งอักขระพิเศษที่ไม่สามารถใช้ใน URL ได้ เช่น ช่องว่าง ( ), เครื่องหมาย &, หรือ ? จะถูกแทนที่ด้วยโค้ดเฉพาะเช่น %20 สำหรับช่องว่าง เพื่อให้มั่นใจว่า URL จะไม่เกิดข้อผิดพลาดเมื่อส่งข้อมูลผ่านโปรโตคอล HTTP
  • UrlDecode: ทำงานตรงกันข้ามกับ UrlEncode โดยจะถอดรหัส URL กลับไปเป็นรูปแบบที่สามารถอ่านได้ เช่น:
    • %20 จะถูกถอดรหัสเป็นช่องว่าง ( )

ตัวอย่างการใช้งาน UrlEncode และ UrlDecode ใน AL

procedure UrlEncodeExample()
var
    InputUrl: Text;
    EncodedUrl: Text;
    DecodedUrl: Text;
begin
    // ข้อมูล URL ที่มีอักขระพิเศษ
    InputUrl := 'https://www.example.com?name=Thanapope & age=30';
    
    // เข้ารหัส URL
    EncodedUrl := TypeHelper.UrlEncode(InputUrl);
    Message('Encoded URL: %1', EncodedUrl); // จะแสดง: https%3A%2F%2Fwww.example.com%3Fname%3DThanapope%20%26%20age%3D30
    
    // ถอดรหัส URL
    DecodedUrl := TypeHelper.UrlDecode(EncodedUrl);
    Message('Decoded URL: %1', DecodedUrl); // จะแสดง: https://www.example.com?name=Thanapope & age=30
end;

สรุป

ฟังก์ชัน HtmlEncode และ HtmlDecode ใช้ในการจัดการกับอักขระพิเศษใน HTML เพื่อการแสดงผลที่ปลอดภัยและถูกต้อง ขณะที่ UrlEncode และ UrlDecode ใช้สำหรับการเข้ารหัสและถอดรหัสข้อมูลใน URL ซึ่งเป็นการป้องกันปัญหาจากอักขระที่ไม่สามารถใช้งานได้ใน URL

Dynamics 365 Business Central: การใช้งาน Base64 Convert Codeunit ใน AL Programming

Base64 Convert Codeunit เป็นหนึ่งในฟังก์ชันที่สำคัญใน AL programming ซึ่งใช้สำหรับการเข้ารหัส (encode) และถอดรหัส (decode) ข้อมูลในรูปแบบ Base64 โดย Base64 เป็นรูปแบบการเข้ารหัสข้อมูลที่นิยมใช้ในการส่งข้อมูลในโปรโตคอลต่างๆ เช่น HTTP หรือในการจัดเก็บข้อมูลที่ต้องการให้เป็นรูปแบบข้อความ

ฟังก์ชันหลักใน Base64 Convert Codeunit

  1. ToBase64
    • ใช้ในการเข้ารหัสข้อความหรือข้อมูลจาก InStream เป็น Base64
    • รองรับตัวเลือกในการแทรก Line Breaks ทุก ๆ 76 ตัวอักษรและระบุ TextEncoding เช่น UTF-8, MsDos, หรือ Windows
  2. FromBase64
    • ใช้ในการถอดรหัสข้อมูลจาก Base64 กลับเป็นข้อความปกติ
    • รองรับการระบุ TextEncoding และการถอดรหัสข้อมูลจาก Base64 ลงใน OutStream

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

1. การเข้ารหัสข้อความธรรมดาเป็น Base64

procedure EncodeTextToBase64(InputText: Text): Text
var
    Base64: Codeunit "Base64 Convert";
begin
    exit(Base64.ToBase64(InputText)); // คืนค่าข้อความที่ถูกเข้ารหัสเป็น Base64
end;

การใช้งาน

var
    EncodedText: Text;
begin
    EncodedText := EncodeTextToBase64('Hello World!');
    Message('Encoded Base64: %1', EncodedText);
end;

อธิบาย: ในตัวอย่างนี้ ข้อความ Hello World! จะถูกเข้ารหัสเป็น Base64 ซึ่งสามารถนำไปใช้งานในระบบต่าง ๆ ได้ เช่น การส่งข้อมูลผ่าน API

2. การเข้ารหัสพร้อมแทรก Line Breaks

procedure EncodeTextWithLineBreaks(InputText: Text): Text
var
    Base64: Codeunit "Base64 Convert";
begin
    exit(Base64.ToBase64(InputText, true)); // คืนค่าข้อความที่ถูกเข้ารหัสพร้อมแทรก line breaks ทุก ๆ 76 ตัวอักษร
end;

การใช้งาน

var
    EncodedTextWithBreaks: Text;
begin
    EncodedTextWithBreaks := EncodeTextWithLineBreaks('This is a very long string that we are using to demonstrate how Base64 encoding works when we have more than seventy-six characters in the input text.');
    Message('Encoded Text with Line Breaks: %1', EncodedTextWithBreaks);
end;

อธิบาย: การเข้ารหัสพร้อม InsertLineBreaks จะทำให้ข้อความ Base64 ถูกแบ่งบรรทัดทุก ๆ 76 ตัวอักษร ซึ่งมีประโยชน์ในบางกรณีที่ต้องการความอ่านง่ายหรือการจำกัดความยาวบรรทัด

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

1. การถอดรหัสข้อความ Base64 กลับเป็นข้อความปกติ

procedure DecodeBase64ToText(Base64String: Text): Text
var
    Base64: Codeunit "Base64 Convert";
begin
    exit(Base64.FromBase64(Base64String)); // คืนค่าข้อความที่ถอดรหัสจาก Base64
end;

การใช้งาน

var
    DecodedText: Text;
begin
    DecodedText := DecodeBase64ToText('SGVsbG8gV29ybGQh');
    Message('Decoded Text: %1', DecodedText);
end;

อธิบาย: ข้อความ SGVsbG8gV29ybGQh ซึ่งเป็นข้อความที่เข้ารหัสใน Base64 จะถูกถอดรหัสกลับมาเป็น Hello World!

2. การถอดรหัสข้อมูลจาก Stream

procedure DecodeStreamFromBase64(Base64String: Text; var OutStream: OutStream)
var
    Base64: Codeunit "Base64 Convert";
begin
    Base64.FromBase64(Base64String, OutStream); // ถอดรหัสข้อมูลจาก Base64 แล้วนำไปเก็บใน OutStream
end;

การใช้งาน

var
    OutStream: OutStream;
begin
    DecodeStreamFromBase64('SGVsbG8gV29ybGQh', OutStream);
    // ทำงานกับ OutStream ต่อไป
end;

อธิบาย: ในตัวอย่างนี้ ข้อมูลจะถูกถอดรหัสจาก Base64 แล้วถูกเก็บไว้ใน OutStream ซึ่งสามารถนำไปใช้งานในรูปแบบข้อมูล Stream อื่น ๆ ได้

สรุป

Base64 Convert Codeunit เป็นเครื่องมือที่มีประโยชน์ในการจัดการข้อมูล Base64 ไม่ว่าจะเป็นการเข้ารหัสหรือถอดรหัส โดยมีฟังก์ชันที่ยืดหยุ่นและรองรับการทำงานทั้งในรูปแบบข้อความปกติและ Stream ทำให้สามารถนำไปประยุกต์ใช้ในโปรเจ็กต์ต่างๆ ในระบบ Dynamics 365 Business Central ได้อย่างมีประสิทธิภาพ

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

ใน AL Programming การใช้งาน Control Statements เป็นสิ่งที่จำเป็นสำหรับการควบคุมการทำงานของโปรแกรม AL คำสั่งเหล่านี้ช่วยให้โปรแกรมเมอร์สามารถเขียนโค้ดที่ตอบสนองตามเงื่อนไขต่างๆ ดำเนินการคำสั่งที่หลากหลาย หรือทำซ้ำการทำงานตามจำนวนครั้งที่กำหนดได้ Control Statements แบ่งออกเป็นสามประเภทหลักๆ ดังนี้: Compound Statements, Conditional Statements, และ Repetitive Statements

1. AL Compound Statements

AL Compound Statements คือการรวมคำสั่งหลายๆ คำสั่งไว้ในกลุ่มเดียวกัน หรือบล็อกคำสั่ง โดยใช้ begin และ end คำสั่งเหล่านี้จะถูกดำเนินการตามลำดับ

ตัวอย่าง

procedure UpdateCustomerInfo(CustomerNo: Code[20])
var
    Customer: Record Customer;
begin
    if Customer.Get(CustomerNo) then begin
        Customer.Name := 'New Customer Name';
        Customer.Address := '123 New Street';
        Customer.City := 'Bangkok';
        Customer.Modify(true);
    end else
        Error('Customer not found.');
end;

อธิบาย: ในตัวอย่างนี้ begin และ end ถูกใช้เพื่อรวมหลายคำสั่งไว้ในบล็อกเดียว ซึ่งช่วยให้สามารถทำงานหลายคำสั่ง เช่น การเปลี่ยนชื่อ ที่อยู่ และเมืองของลูกค้า ภายในขั้นตอนเดียว

2. AL Conditional Statements

AL Conditional Statements ใช้ในการตัดสินใจว่าคำสั่งใดจะถูกดำเนินการโดยอ้างอิงจากเงื่อนไขที่กำหนดไว้ Conditional Statements ใน AL ประกอบด้วย If-Then-Else และ Case.

2.1 If-Then-Else Statement

If-Then-Else ใช้ในการตรวจสอบเงื่อนไขและดำเนินการคำสั่งตามเงื่อนไขนั้น ถ้าเงื่อนไขเป็นจริงจะดำเนินการคำสั่งในส่วน Then แต่ถ้าไม่เป็นจริงจะดำเนินการในส่วน Else (ถ้ามี)

ตัวอย่าง

procedure CalculateShippingFee(Weight: Decimal): Decimal
var
    ShippingFee: Decimal;
begin
    if Weight <= 5 then
        ShippingFee := 50.00
    else if Weight <= 10 then
        ShippingFee := 100.00
    else
        ShippingFee := 150.00;

    exit(ShippingFee);
end;

อธิบาย: ในตัวอย่างนี้ ค่าธรรมเนียมการขนส่งจะถูกคำนวณตามน้ำหนักของพัสดุ โดยใช้ If-Then-Else statement ถ้าน้ำหนักน้อยกว่า 5 กิโลกรัม ค่าธรรมเนียมจะเป็น 50 บาท ถ้าอยู่ระหว่าง 5-10 กิโลกรัม จะเป็น 100 บาท และถ้ามากกว่า 10 กิโลกรัมจะเป็น 150 บาท

2.2 Case Statement

Case ใช้ในการเลือกคำสั่งที่เหมาะสมจากหลายๆ ตัวเลือก โดยอ้างอิงจากค่าของ Expression ที่กำหนดไว้

ตัวอย่าง

procedure GetCustomerCategory(CustomerPoints: Integer): Text
var
    Category: Text;
begin
    case CustomerPoints of
        0..100:
            Category := 'Bronze';
        101..500:
            Category := 'Silver';
        501..1000:
            Category := 'Gold';
        else
            Category := 'Platinum';
    end;

    exit(Category);
end;

อธิบาย: ในตัวอย่างนี้ Case statement ถูกใช้เพื่อกำหนดประเภทของลูกค้าตามคะแนนที่ลูกค้าได้สะสมไว้ ถ้าคะแนนอยู่ระหว่าง 0-100 จะถูกจัดเป็น Bronze, 101-500 จะเป็น Silver, 501-1000 จะเป็น Gold และมากกว่า 1000 จะเป็น Platinum

3. AL Repetitive Statements

AL Repetitive Statements หรือที่เรียกว่าการทำซ้ำ ใช้ในการทำงานซ้ำๆ จนกว่าจะถึงเงื่อนไขที่กำหนดไว้ ประกอบด้วย For, While, และ Repeat-Until.

3.1 For Loop

For Loop ใช้ในการทำซ้ำคำสั่งตามจำนวนครั้งที่กำหนด โดยใช้ตัวแปรควบคุมการนับ

ตัวอย่าง

procedure CalculateTotalItems(NumItems: Integer): Integer
var
    i: Integer;
    Total: Integer;
begin
    Total := 0;
    for i := 1 to NumItems do
        Total := Total + 1;

    exit(Total);
end;

อธิบาย: ในตัวอย่างนี้ For Loop ถูกใช้ในการนับจำนวนรายการทั้งหมด โดยลูปจะทำซ้ำจาก 1 จนถึงค่าที่กำหนด (NumItems) และเพิ่มค่า Total ทีละ 1 ในแต่ละรอบลูป

3.2 While Loop

While Loop ใช้ในการทำซ้ำคำสั่งตราบใดที่เงื่อนไขยังคงเป็นจริง โดยตรวจสอบเงื่อนไขก่อนการทำงาน

ตัวอย่าง

procedure CalculateInventory(AvailableQty: Decimal): Decimal
var
    NeededQty: Decimal;
begin
    NeededQty := 100;
    while AvailableQty < NeededQty do begin
        AvailableQty := AvailableQty + 10;
    end;

    exit(AvailableQty);
end;

อธิบาย: ในตัวอย่างนี้ While Loop จะทำการเพิ่มจำนวนสินค้าคงเหลือ (AvailableQty) ทีละ 10 จนกว่าจะเพียงพอต่อความต้องการ (NeededQty)

3.3 Repeat-Until Loop

Repeat-Until Loop คล้ายกับ While Loop แต่จะตรวจสอบเงื่อนไขหลังจากที่ทำงานไปแล้วอย่างน้อยหนึ่งครั้ง

ตัวอย่าง

procedure CalculateTotalOutstandingBalance(var CustLedgerEntries: Record "Cust. Ledger Entry"): Decimal
var
    TotalBalance: Decimal;
begin
    TotalBalance := 0;
    if CustLedgerEntries.FindSet() then begin
        repeat
            TotalBalance := TotalBalance + CustLedgerEntries.Amount;
        until CustLedgerEntries.Next() = 0;
    end;
    
    exit(TotalBalance);
end;

อธิบาย: ในตัวอย่างนี้ เราใช้ Repeat-Until Loop เพื่อวนซ้ำใน Record Cust. Ledger Entry เพื่อคำนวณยอดรวมคงเหลือ (TotalBalance) โดยจะทำการบวกยอดในแต่ละบรรทัดของ CustLedgerEntries.Amount จนกว่าจะสิ้นสุด Record (Next() = 0)

สรุป

การใช้ AL Control Statements ไม่ว่าจะเป็น Compound, Conditional, หรือ Repetitive Statements เป็นเครื่องมือสำคัญในการควบคุมการทำงานของโปรแกรม ช่วยให้โปรแกรมเมอร์สามารถสร้างโค้ดที่มีความยืดหยุ่นและตอบสนองต่อสถานการณ์ต่างๆ ได้อย่างมีประสิทธิภาพ

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

EventSubscriber เป็นเครื่องมือที่มีประสิทธิภาพใน AL programming ซึ่งช่วยให้นักพัฒนาสามารถเชื่อมต่อโค้ดของตัวเองเข้ากับ event ที่มีอยู่ใน Dynamics 365 Business Central โดยไม่ต้องแก้ไขโค้ดต้นฉบับ (base code) การใช้งาน EventSubscriber จะช่วยให้เราสามารถขยายฟังก์ชันการทำงานของระบบได้อย่างง่ายดาย ปลอดภัย และไม่มีผลกระทบต่อการอัปเดตของระบบ ทำให้เหมาะสำหรับการพัฒนาระบบที่ต้องการความยืดหยุ่นในการบำรุงรักษาในอนาคต

โครงสร้างพื้นฐานของ EventSubscriber

การใช้งาน EventSubscriber ใน AL ต้องเริ่มต้นด้วยการกำหนดฟังก์ชันที่เราต้องการให้ทำงานเมื่อเหตุการณ์ที่ต้องการเกิดขึ้น โดยใช้ Attribute [EventSubscriber] เพื่อกำหนดลักษณะของการทำงาน

[EventSubscriber(ObjectType::ObjectType, ObjectId: Integer, EventName: Text, ElementName: Text, SkipOnMissingLicense: Boolean, SkipOnMissingPermission: Boolean)]
procedure MyEventSubscriber(Rec: Record <TableName>)
begin
    // การทำงานที่ต้องการเมื่อเกิด Event
end;

รายละเอียดพารามิเตอร์

  • ObjectType: ระบุประเภทของ Object ที่สร้างเหตุการณ์ เช่น Table, Codeunit, Page
  • ObjectId: ระบุ ID ของ Object หรือชื่อ Object ที่ต้องการติดตาม
  • EventName: ระบุชื่อของเหตุการณ์ที่ต้องการติดตาม เช่น OnAfterInsertEvent
  • ElementName: ใช้กับเหตุการณ์ที่เกี่ยวกับฟิลด์ในตาราง (เช่น OnAfterValidateEvent)
  • SkipOnMissingLicense: ระบุว่าจะข้ามการเรียก EventSubscriber หาก License ไม่มีสิทธิ์การเข้าถึง
  • SkipOnMissingPermission: ระบุว่าจะข้ามการเรียก EventSubscriber หากผู้ใช้ไม่มีสิทธิ์การเข้าถึง

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

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

[EventSubscriber(ObjectType::Table, Database::Customer, 'OnAfterModifyEvent', '', false, false)]
local procedure CheckImportantFieldsAfterModify(Rec: Record Customer; xRec: Record Customer)
begin
    if Rec.Name <> xRec.Name then
        Message('Customer Name has been changed from %1 to %2', xRec.Name, Rec.Name);
end;

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

  • ObjectType คือ Table แสดงว่ากำลังติดตามเหตุการณ์ในระดับตาราง
  • ObjectId คือ Database::Customer ซึ่งเป็นตารางลูกค้าที่เราต้องการติดตาม
  • EventName คือ OnAfterInsertEvent เหตุการณ์ที่เกิดขึ้นหลังจากเพิ่มลูกค้าใหม่
  • ElementName เป็นค่าว่าง เนื่องจากเราไม่ได้ติดตามการ Validate ฟิลด์เฉพาะเจาะจง
  • SkipOnMissingLicense และ SkipOnMissingPermission กำหนดเป็น false เพื่อให้ฟังก์ชันทำงานในทุกสถานการณ์ที่ผู้ใช้มีสิทธิ์และ License เพียงพอ

การใช้งาน EventSubscriber ในสถานการณ์ต่าง ๆ

  1. การตรวจสอบข้อมูลก่อนการบันทึก: EventSubscriber สามารถใช้ตรวจสอบความถูกต้องของข้อมูลก่อนที่จะถูกบันทึกลงฐานข้อมูล เช่น การตรวจสอบว่าชื่อลูกค้าไม่ควรเป็นค่าว่าง
  2. การเพิ่มฟังก์ชันการทำงาน: สามารถเพิ่มฟังก์ชันใหม่ที่ทำงานเมื่อเกิดเหตุการณ์เฉพาะ เช่น การคำนวณหรืออัปเดตฟิลด์เมื่อมีการเปลี่ยนแปลงข้อมูล
  3. การจัดการการทำงานในระดับ Page: EventSubscriber สามารถใช้ในการติดตามเหตุการณ์ที่เกิดขึ้นในหน้าจอต่างๆ เช่น การกดปุ่ม หรือการเลือกค่าใน Drop-down

สรุป

การใช้งาน EventSubscriber ใน AL Programming ช่วยให้เราสามารถสร้างฟังก์ชันการทำงานเพิ่มเติมเพื่อให้ระบบมีความสามารถในการตอบสนองต่อเหตุการณ์ต่าง ๆ ได้อย่างยืดหยุ่นและปลอดภัย โดยไม่ต้องแก้ไขโค้ดของ object เดิม ช่วยเพิ่มความเสถียรและความยืดหยุ่นในการพัฒนาระบบได้มากยิ่งขึ้น