Skip to main content

Business Central Setup Table Generator

Generates setup tables and pages following Microsoft's singleton pattern for Business Central extensions. Creates single-record tables for module configuration with automatic initialization and performance-optimized access patterns.

Overview

Setup tables are singleton tables (one record per company) used to store module-wide configuration. This skill generates:

  • Setup table with singleton pattern
  • Setup page (Card) with auto-initialization
  • GetRecordOnce helper for performance
  • Common field patterns

Advanced patterns and variations: references/patterns.md

Prerequisites

  • AL workspace with established object ID range
  • Module/feature name defined
  • Prefix established (e.g., BCS, CUSTOM, etc.)
  • List of configuration settings to expose

Quick Start

1. Basic Setup Table Structure

table [ID] "[Prefix] [Module] Setup"
{
Caption = '[Module] Setup';
DataClassification = CustomerContent;
DrillDownPageID = "[Prefix] [Module] Setup";
LookupPageID = "[Prefix] [Module] Setup";

fields
{
field(1; "Primary Key"; Code[10])
{
Caption = 'Primary Key';
DataClassification = SystemMetadata;
AllowInCustomizations = Never;
}
}

keys
{
key(PK; "Primary Key")
{
Clustered = true;
}
}
}

Key Properties:

  • DataClassification: Use CustomerContent for business data, SystemMetadata for technical fields
  • DrillDownPageID / LookupPageID: Point to setup page for seamless navigation
  • Primary Key field: Always Code[10], never visible to user

2. Setup Page with Auto-Initialization

page [ID] "[Prefix] [Module] Setup"
{
ApplicationArea = All;
Caption = '[Module] Setup';
PageType = Card;
SourceTable = "[Prefix] [Module] Setup";
UsageCategory = Administration;
DeleteAllowed = false;
InsertAllowed = false;

layout
{
area(Content)
{
group(General)
{
Caption = 'General';

// Add fields here
}
}
}

trigger OnOpenPage()
begin
Rec.Reset();
if not Rec.Get() then begin
Rec.Init();
Rec.Insert();
end;
end;
}

Key Properties:

  • PageType = Card: Single-record view
  • UsageCategory = Administration: Shows in search results under Administration
  • DeleteAllowed/InsertAllowed = false: Prevents accidental deletion/duplication
  • OnOpenPage: Auto-creates record if missing (singleton pattern)

Add to setup table for performance optimization:

table [ID] "[Prefix] [Module] Setup"
{
// ... fields and keys ...

procedure GetRecordOnce()
begin
if IsInitialized then
exit;

if not Get() then begin
Init();
Insert();
end;

IsInitialized := true;
end;

var
IsInitialized: Boolean;
}

Usage Pattern:

// In consuming codeunits
local procedure GetDefaultValue(): Text[50]
var
[Prefix]Setup: Record "[Prefix] [Module] Setup";
begin
[Prefix]Setup.GetRecordOnce();
exit([Prefix]Setup."Default Value");
end;

Performance Benefit: GetRecordOnce caches record in memory, avoiding repeated database reads.

Common Field Patterns

Pattern 1: Enable/Disable Features

field(10; "Enable Feature"; Boolean)
{
Caption = 'Enable Feature';
DataClassification = CustomerContent;
ToolTip = 'Specifies whether the feature is enabled.';
}

ToolTip Rule: Always start with "Specifies..." for setup fields.

Pattern 2: Number Series References

field(20; "Document Nos."; Code[20])
{
Caption = 'Document Nos.';
DataClassification = CustomerContent;
TableRelation = "No. Series";
ToolTip = 'Specifies the number series used for document numbers.';
}

TableRelation: Points to No. Series table for dropdown lookup.

Pattern 3: Default Values

field(30; "Default Location"; Code[10])
{
Caption = 'Default Location';
DataClassification = CustomerContent;
TableRelation = Location;
ToolTip = 'Specifies the default location for operations.';
}

Pattern 4: User ID References

field(40; "Default User ID"; Code[50])
{
Caption = 'Default User ID';
DataClassification = EndUserIdentifiableInformation;
TableRelation = User."User Name";
ToolTip = 'Specifies the default user for automated operations.';
}

DataClassification: Use EndUserIdentifiableInformation for user references.

Pattern 5: API Integration Settings

field(50; "API Base URL"; Text[250])
{
Caption = 'API Base URL';
DataClassification = CustomerContent;
ExtendedDatatype = URL;
ToolTip = 'Specifies the base URL for the external API.';
}

field(51; "API Key"; Text[100])
{
Caption = 'API Key';
DataClassification = EndUserIdentifiableInformation;
ExtendedDatatype = Masked;
ToolTip = 'Specifies the API key for authentication.';
}

ExtendedDatatype:

  • URL: Validates URL format
  • Masked: Hides value with asterisks for sensitive data

Pattern 6: File Paths and Directories

field(60; "Export Path"; Text[250])
{
Caption = 'Export Path';
DataClassification = CustomerContent;
ToolTip = 'Specifies the folder path for exported files.';
}

Setup Page Layout Patterns

Group Organization

Organize fields into logical groups:

layout
{
area(Content)
{
group(General)
{
Caption = 'General';
// Basic module settings
}

group("Number Series")
{
Caption = 'Number Series';
// All number series fields
}

group("Integration")
{
Caption = 'Integration';
// API settings, external system config
}

group("Defaults")
{
Caption = 'Defaults';
// Default values for operations
}
}
}

Add actions for common setup tasks:

actions
{
area(Processing)
{
action(ResetToDefaults)
{
ApplicationArea = All;
Caption = 'Reset to Defaults';
Image = Restore;
ToolTip = 'Reset all settings to default values.';
Promoted = true;
PromotedCategory = Process;
PromotedIsBig = true;

trigger OnAction()
begin
if Confirm('Reset all settings to defaults?', false) then begin
Rec.Init();
Rec.Modify();
CurrPage.Update();
Message('Settings have been reset to defaults.');
end;
end;
}

action(TestConnection)
{
ApplicationArea = All;
Caption = 'Test Connection';
Image = TestDatabase;
ToolTip = 'Test connection to external system.';
Promoted = true;
PromotedCategory = Process;

trigger OnAction()
begin
// Test connection logic
end;
}
}
}

Implementation Workflow

Step 1: Gather Requirements

Ask user for:

  • Module name (e.g., "Statistical Accounts", "Custom Workflow")
  • Prefix (e.g., "BCS")
  • Object IDs (table and page)
  • List of settings/fields needed
  • Field logical groupings

Step 2: Create Setup Table

  1. Create table file: [Prefix][Entity]Setup.Table.al
  2. Add primary key field
  3. Add DrillDownPageID and LookupPageID properties
  4. Add configuration fields with proper:
    • DataClassification
    • TableRelation (for lookups)
    • ExtendedDatatype (for URLs, masked values)
    • ToolTip (starting with "Specifies...")

Add GetRecordOnce procedure and IsInitialized variable to table for performance.

Step 4: Create Setup Page

  1. Create page file: [Prefix][Entity]Setup.Page.al
  2. Set PageType = Card
  3. Set UsageCategory = Administration
  4. Disable DeleteAllowed and InsertAllowed
  5. Add OnOpenPage initialization trigger
  6. Organize fields into logical groups
  7. Add relevant actions (Reset to Defaults, Test Connection, etc.)

Step 5: Validation and Testing

  • Build to check for compilation errors
  • Test page opens and auto-creates record
  • Verify lookups work (Number Series, TableRelations)
  • Test GetRecordOnce caching behavior
  • Validate ToolTips display correctly

Step 6: Permission Set

Generate or update permission set to include:

  • Setup table (RIMD permissions)
  • Setup page (Read permission)

Pre-Flight Checklist

Before generating, verify:

  • Object IDs available and in valid range
  • Prefix follows project conventions
  • Module name is clear and descriptive
  • All required configuration fields identified
  • Field groupings planned
  • DataClassification determined for each field
  • TableRelation targets identified for lookup fields
  • ToolTip text prepared for all fields

Common Variations

Multi-Tab Setup Pages

For complex modules with many settings:

layout
{
area(Content)
{
group(General)
{
// General settings
}
}

area(FactBoxes)
{
// Related information
}
}

Or use FastTabs:

layout
{
area(Content)
{
group(GeneralTab)
{
Caption = 'General';
// Fields
}

group(IntegrationTab)
{
Caption = 'Integration';
// Fields
}
}
}

See references/patterns.md for advanced multi-tab patterns.

Setup with Validation

Add field validation for complex rules:

field(10; "Max Retry Count"; Integer)
{
Caption = 'Max Retry Count';
DataClassification = CustomerContent;
MinValue = 1;
MaxValue = 10;

trigger OnValidate()
begin
if "Max Retry Count" > 5 then
if not Confirm('Values above 5 may impact performance. Continue?') then
Error('');
end;
}

Setup with Table Extension Pattern

For extending base BC setup tables:

tableextension [ID] "[Prefix] [Base Setup]" extends "[Base Setup Table]"
{
fields
{
field([ID]; "[Prefix] Custom Field"; Boolean)
{
Caption = 'Custom Field';
DataClassification = CustomerContent;
}
}
}

pageextension [ID] "[Prefix] [Base Setup]" extends "[Base Setup Page]"
{
layout
{
addlast(Content)
{
group("[Prefix] Custom")
{
Caption = 'Custom Settings';

field("[Prefix] Custom Field"; Rec."[Prefix] Custom Field")
{
ApplicationArea = All;
}
}
}
}
}

See references/patterns.md for complete setup extension patterns.

Best Practices

  1. Singleton Enforcement: Always use OnOpenPage to auto-create record
  2. Prevent Deletion: Set DeleteAllowed = false, InsertAllowed = false
  3. Use GetRecordOnce: Cache record for repeated access in same transaction
  4. Organize with Groups: Group related fields logically
  5. Meaningful ToolTips: Start with "Specifies..." and provide clear guidance
  6. Proper DataClassification:
    • CustomerContent for business data
    • EndUserIdentifiableInformation for user references, API keys
    • SystemMetadata for technical fields (Primary Key)
  7. UsageCategory = Administration: Makes setup findable via search
  8. DrillDown/Lookup Pages: Point to setup page for seamless navigation

External References

Version

Initial release: 1.0.0