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.
AL event subscriber
alSubscribe 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;AL test codeunit (arrange-act-assert)
alThe 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;AL table extension
alAdding 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;
}
}
}Power Fx named formula
powerfxA 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;Power Fx Patch with error handling
powerfxPatch 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)
);FetchXML query with a filter
fetchxmlA 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>Dataverse Web API OData filter query
httpThe 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.0Dataverse Web API batch request (reduces call count)
httpBatch 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--