Understanding GETRANGEMIN() and GETRANGEMAX() in Business Central

When working with filters and record ranges in AL , two handy functions often come into play: GETRANGEMIN() and GETRANGEMAX(). These functions help you programmatically access the lower and upper bounds of a filter applied to a field in a record. This can be especially useful for creating reports, processing data, or passing filters between records.

What are GETRANGEMIN() and GETRANGEMAX()?

These two functions are part of the Record data type and help retrieve the range boundaries for a specific field filter.

  • GETRANGEMIN(Field): Returns the lowest value in the filter range for the specified field.
  • GETRANGEMAX(Field): Returns the highest value in the filter range for the specified field.

If there is no filter set for the field, both functions return blank.

SalesHeader.SETFILTER("No.", '1000..2000');

MinNo := SalesHeader.GETRANGEMIN("No."); // Returns '1000'
MaxNo := SalesHeader.GETRANGEMAX("No."); // Returns '2000'

Use Cases

1. Transferring Filter Ranges

If you’re applying a filter on one table and want to use the same range on another:

Customer.SETFILTER("No.", 'C00010..C00020');
SalesHeader.SETRANGE("Sell-to Customer No.", Customer.GETRANGEMIN("No."), Customer.GETRANGEMAX("No."));

2. Generating Custom Reports

SalesHeader.SETFILTER("Posting Date", '2024-01-01..2024-01-31');

StartDate := SalesHeader.GETRANGEMIN("Posting Date");
EndDate := SalesHeader.GETRANGEMAX("Posting Date");

MESSAGE('Report for: %1 to %2', StartDate, EndDate);

3. Validating Filtered Data

IF (SalesHeader.GETRANGEMIN("Posting Date") < AllowedStartDate) OR
   (SalesHeader.GETRANGEMAX("Posting Date") > AllowedEndDate) THEN
    ERROR('Filter range is outside allowed period.');

The GETRANGEMIN() and GETRANGEMAX() functions are powerful tools when working with dynamic filters in AL. They enable developers to write cleaner, more adaptable code by directly accessing the boundaries of filter conditions.

Stay Tuned for more updates.

FieldRef.IsOptimizedForTextSearch() Method in Business Central 2025 Wave 1

With the release of Business Central 2025 Wave 1, Microsoft continues to empower developers with more control and insights into the performance and behavior of their extensions. Among the new additions is the method FieldRef.IsOptimizedForTextSearch(), designed to help developers make more performance-conscious decisions when implementing search functionalities.

💡 What is FieldRef.IsOptimizedForTextSearch()?

FieldRef.IsOptimizedForTextSearch() is a method that returns a Boolean value indicating whether a particular field in a table is optimized for text search.

It is a method on the FieldRef data type, which is used in AL code to dynamically refer to fields of records, especially in scenarios involving field iteration, metadata handling, or dynamic filters.

✅ Syntax:

Boolean := FieldRef.IsOptimizedForTextSearch();

⚙️ How to Optimize a Field for Text Search

While IsOptimizedForTextSearch() only checks if a field is optimized, setting it up is done via the table metadata or through the table schema in AL.

To mark a field for text search:

field(10; Description; Text[100])
{
Caption = 'Description';
DataClassification = ToBeClassified;
OptimizeForTextSearch = true;
}

Setting OptimizeForTextSearch = true; enables text search optimization (depending on SQL backend settings as well for on-premise).

Lets see how we can utlize above method to check optimize search

var
    MyRecordRef: RecordRef;
    MyFieldRef: FieldRef;
    IsOptimized: Boolean;
begin
    MyRecordRef.Open(Database::Customer);
    if MyRecordRef.FindSet() then begin
        MyFieldRef := MyRecordRef.Field(Name); // Let's check the "Name" field
        IsOptimized := MyFieldRef.IsOptimizedForTextSearch();

        if IsOptimized then
            Message('The "%1" field in the Customer table is optimized for text search.', MyFieldRef.Name())
        else
            Message('The "%1" field in the Customer table is NOT optimized for text search.', MyFieldRef.Name());
    end;
    MyRecordRef.Close();
end;

To be optimized for full-text search, a field typically needs:

  • A Text or Code data type.
  • An active index that supports full-text search (defined in the table metadata or via table extensions).
  • Proper settings in SQL Server or Azure SQL (if full-text search is enabled).

The FieldRef.IsOptimizedForTextSearch() method is a small but powerful tool in the AL developer’s toolkit. Whether you’re designing smarter search UIs or optimizing performance in large datasets, this method gives you the metadata visibility to make informed choices.

By leveraging this feature, you can:

  • Improve app performance
  • Avoid slow queries
  • Create better user experiences

Stay tuned for more..

Implicit Record and Record Ref Conversion in Business Central AL

When working with Microsoft Dynamics 365 Business Central, one of the most powerful capabilities is the dynamic handling of data using RecordRef. However, as a developer, you may have run into scenarios where you need to switch between the strongly typed Record and the flexible RecordRef—and wondered if there’s a clean way to do it.

Good news: Business Central now supports implicit conversion between Record and RecordRef

📘 Understanding the Core Types:

Before exploring the implicit conversion, it’s crucial to understand the distinct roles of Record and RecordRef:

  • Record: A strongly-typed variable that represents a specific table in the Business Central database. The compiler enforces type safety, ensuring that operations performed on a Record variable are valid for the defined table structure.
  • RecordRef: A more dynamic variable that provides a generic reference to any table in the Business Central database. It allows for runtime manipulation of table structures and data, often used in scenarios like generic data access, metadata exploration, and dynamic query building.

Implicit Conversion – What’s New?

With recent updates, AL now supports implicit conversion:

  • From a Record to a RecordRef
  • From a RecordRef back to a Record (if the types match)

This means cleaner, safer, and more readable code without the boilerplate RecordRef.GetTable() or RecordRef.SetTable().

🔍 Example: Record to RecordRef

procedure LogAnyRecord(rec: RecordRef)
begin
    Message('Table ID: %1', rec.Number);
end;

procedure RunLogging()
var
    customer: Record Customer;
begin
    customer.Get('10000');
    LogAnyRecord(customer); // Implicit conversion from Record to RecordRef
end;

No need for recRef.SetTable(customer) — it’s handled under the hood.

🔄 Example: RecordRef to Record

procedure GetCustomerName(recRef: RecordRef): Text
var
    customer: Record Customer;
begin
    customer := recRef; // Implicit conversion from RecordRef to Record
    exit(customer.Name);
end;

Implicit conversions between Record and RecordRef bring AL language making it easier to write dynamic yet type-safe code. While it’s a small feature on the surface, it greatly enhances developer productivity and code clarity.

Stay Tuned for more updates.