Snippets

AL, Power Fx, FetchXML, and OData patterns that recur across Dynamics 365 development — copy-paste ready, with a back-link to the guide that explains each in context.

alpowerfxfetchxmlhttp

AL event subscriber

al

Subscribe to a standard Business Central event without modifying the base object — the extension-safe way to react to something the platform already raises.

[EventSubscriber(ObjectType::Codeunit, Codeunit::"Sales-Post", 'OnAfterPostSalesDoc', '', false, false)]
local procedure OnAfterPostSalesDoc(var SalesHeader: Record "Sales Header"; SalesInvoiceHeader: Record "Sales Invoice Header")
begin
    // React to a posted sales document without touching Sales-Post itself.
    if SalesInvoiceHeader."No." <> '' then
        NotifyDownstreamSystem(SalesInvoiceHeader."No.");
end;
Explained in context →

AL test codeunit (arrange-act-assert)

al

The standard shape for an AL unit test, using the Test Library helpers instead of hand-building test data.

[Test]
procedure LineDiscountAppliesAboveThreshold()
var
    Customer: Record Customer;
    Item: Record Item;
    SalesHeader: Record "Sales Header";
    SalesLine: Record "Sales Line";
    LibrarySales: Codeunit "Library - Sales";
    LibraryInventory: Codeunit "Library - Inventory";
    Assert: Codeunit Assert;
begin
    // Arrange
    LibrarySales.CreateCustomer(Customer);
    LibraryInventory.CreateItem(Item);
    LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader."Document Type"::Order, Customer."No.");
    LibrarySales.CreateSalesLine(SalesLine, SalesHeader, SalesLine.Type::Item, Item."No.", 100);

    // Act
    SalesLine.Validate(Quantity, 100);
    SalesLine.Modify(true);

    // Assert
    Assert.IsTrue(SalesLine."Line Discount %" > 0, 'Expected a volume discount above threshold.');
end;
Explained in context →

AL table extension

al

Adding a field to a standard table without touching Microsoft's own object — the extension model in one block.

tableextension 50100 "Customer Ext" extends Customer
{
    fields
    {
        field(50100; "Preferred Delivery Day"; Enum "Day of Week")
        {
            Caption = 'Preferred Delivery Day';
            DataClassification = CustomerContent;
        }
    }
}
Explained in context →

Power Fx named formula

powerfx

A named formula recalculates automatically like a spreadsheet cell — no OnStart, no manual variable assignment.

// App-level named formula (App OnFormulaLoad / App formulas):
DiscountThreshold = 1000;
IsHighValueOrder = Sum(OrderLines, Quantity * UnitPrice) > DiscountThreshold;
Explained in context →

Power Fx Patch with error handling

powerfx

Patch against Dataverse and surface a real error instead of a silent failure a user won't notice.

IfError(
    Patch(
        Accounts,
        Defaults(Accounts),
        { Name: TextInput1.Text, 'Account Number': AccountNumberInput.Text }
    ),
    Notify("Could not save: " & FirstError.Message, NotificationType.Error),
    Notify("Saved", NotificationType.Success)
);
Explained in context →

FetchXML query with a filter

fetchxml

A basic filtered query over accounts — the shape FetchXML Builder in XRMToolBox generates visually.

<fetch top="50">
  <entity name="account">
    <attribute name="name" />
    <attribute name="revenue" />
    <filter type="and">
      <condition attribute="revenue" operator="gt" value="1000000" />
      <condition attribute="statecode" operator="eq" value="0" />
    </filter>
    <order attribute="revenue" descending="true" />
  </entity>
</fetch>
Explained in context →

Dataverse Web API OData filter query

http

The OData equivalent of the FetchXML query above — the modern default for external integrations.

GET [org]/api/data/v9.2/accounts?$select=name,revenue&$filter=revenue gt 1000000 and statecode eq 0&$orderby=revenue desc&$top=50
Authorization: Bearer {token}
OData-MaxVersion: 4.0
OData-Version: 4.0
Explained in context →

Dataverse Web API batch request (reduces call count)

http

Batch multiple operations into one HTTP request — counts as fewer API calls toward the per-user rate limit than the equivalent individual requests.

POST [org]/api/data/v9.2/$batch
Content-Type: multipart/mixed;boundary=batch_123

--batch_123
Content-Type: application/http

PATCH accounts(00000000-0000-0000-0000-000000000001) HTTP/1.1
Content-Type: application/json

{"name":"Updated Name"}
--batch_123--
Explained in context →