If you’ve been developing in Business Central for a while, you’ve probably written your fair share of code to find records based on user input. Maybe you’ve struggled with users typing partial descriptions, or wondered how the system magically finds records when someone enters something that’s not quite an exact match. Well, let me introduce you to one of Business Central’s codeunit to help you with that: Codeunit 703 “Find Record Management”.
What Is Find Record Management?
Think of Find Record Management as your intelligent search assistant. It’s the codeunit that handles all those “fuzzy” searches where users don’t enter exact matches but still expect the system to find what they’re looking for. You know, like when someone types “Blue Widget” and expects the system to find “WIDGET-BLUE-001” or when they enter a partial description and want to see matching items.
The codeunit a collection of methods that make record searching much smarter than your typical FindFirst or FindSet operations.
The Core Methods You Need to Know
Let’s break down the key methods that will make your life easier:
1. FindRecordByDescription – The Smart Search
This is probably the most useful method in the entire codeunit. It takes a search text and a type (like Item, G/L Account, Resource, etc.) and returns matching records based on both the No. field and Description field.
procedure FindRecordByDescription(var Result: Text; Type: Option " ","G/L Account",Item,Resource,"Fixed Asset","Charge (Item)",,,,,"Allocation Account"; SearchText: Text): Integer
What makes this special? It doesn’t just look for exact matches. It uses a sophisticated search algorithm that tries multiple strategies:
- First, it tries to find an exact match on the No. field
- Then it looks for records where the No. starts with the search text
- Next, it searches for exact matches in the Description field
- It also tries pattern matching with wildcards
- Finally, it even attempts fuzzy matching for similar names
Example : Smart Item Lookup in a Sales Order
Let’s say you’re building a custom sales order page where users can type item descriptions instead of memorizing item numbers:
local procedure FindItemByUserInput(UserInput: Text): Code[20]
var
FindRecordMgt: Codeunit "Find Record Management";
Item: Record Item;
Result: Text;
RecordsFound: Integer;
ItemList: Page "Item List";
begin
if UserInput = '' then
exit('');
RecordsFound := FindRecordMgt.FindRecordByDescription(Result, FindRecordMgt.Type::Item, UserInput);
case RecordsFound of
0:
begin
Message('No items found matching "%1"', UserInput);
exit('');
end;
1:
begin
// Perfect match found
if Item.Get(Result) then
exit(Result);
end;
else begin
// Multiple matches - let user choose
Item.SetFilter("No.", Result);
ItemList.SetTableView(Item);
ItemList.LookupMode(true);
if ItemList.RunModal() = Action::LookupOK then begin
ItemList.GetRecord(Item);
exit(Item."No.");
end;
end;
end;
end;
// Usage in a page
trigger OnValidate()
var
ItemNo: Code[20];
begin
ItemNo := FindItemByUserInput(Rec."Item Description");
if ItemNo <> '' then begin
Rec.Validate("No.", ItemNo);
CurrPage.Update(true);
end;
end;
2. FindNoFromTypedValue – The Universal Translator
This method is like having a universal translator for your record lookups:
procedure FindNoFromTypedValue(Type: Option " ","G/L Account",Item,Resource,"Fixed Asset","Charge (Item)",,,,,"Allocation Account"; Value: Code[20]; UseDefaultTableRelationFilters: Boolean): Code[20]
Give it a type and a value, and it will do its best to return a valid No. for that record type. It’s particularly useful when you’re processing data from external sources or user input where you’re not sure if they’ve entered a code or a description.
Example: Smart Data Import with FindNoFromTypedValue
Here’s a practical example of using FindNoFromTypedValue when importing data from external sources where you’re not sure if users entered codes or descriptions:
local procedure ProcessImportLine(ImportType: Text; ImportValue: Text; var ResultNo: Code[20]; var ErrorMessage: Text): Boolean
var
FindRecordMgt: Codeunit "Find Record Management";
TypeOption: Option " ","G/L Account",Item,Resource,"Fixed Asset","Charge (Item)",,,,,"Allocation Account";
FoundNo: Code[20];
Item: Record Item;
GLAccount: Record "G/L Account";
Resource: Record Resource;
begin
Clear(ResultNo);
Clear(ErrorMessage);
// Convert import type to option
case UpperCase(ImportType) of
'ITEM':
TypeOption := TypeOption::Item;
'GLACCOUNT', 'G/L ACCOUNT', 'GL':
TypeOption := TypeOption::"G/L Account";
'RESOURCE':
TypeOption := TypeOption::Resource;
'FIXEDASSET', 'FIXED ASSET', 'FA':
TypeOption := TypeOption::"Fixed Asset";
else begin
ErrorMessage := StrSubstNo('Unsupported import type: %1', ImportType);
exit(false);
end;
end;
// This is the magic - FindNoFromTypedValue will try to find the record
// whether the user entered a code, description, or partial match
FoundNo := FindRecordMgt.FindNoFromTypedValue(TypeOption, CopyStr(ImportValue, 1, 20), true);
if FoundNo <> '' then begin
// Validate that the found record is appropriate for our use
case TypeOption of
TypeOption::Item:
begin
if Item.Get(FoundNo) then begin
if Item.Blocked then begin
ErrorMessage := StrSubstNo('Item %1 (%2) is blocked', FoundNo, Item.Description);
exit(false);
end;
ResultNo := FoundNo;
exit(true);
end;
end;
TypeOption::"G/L Account":
begin
if GLAccount.Get(FoundNo) then begin
if GLAccount.Blocked then begin
ErrorMessage := StrSubstNo('G/L Account %1 (%2) is blocked', FoundNo, GLAccount.Name);
exit(false);
end;
if not GLAccount."Direct Posting" then begin
ErrorMessage := StrSubstNo('G/L Account %1 (%2) does not allow direct posting', FoundNo, GLAccount.Name);
exit(false);
end;
ResultNo := FoundNo;
exit(true);
end;
end;
TypeOption::Resource:
begin
if Resource.Get(FoundNo) then begin
if Resource.Blocked then begin
ErrorMessage := StrSubstNo('Resource %1 (%2) is blocked', FoundNo, Resource.Name);
exit(false);
end;
ResultNo := FoundNo;
exit(true);
end;
end;
end;
end else begin
ErrorMessage := StrSubstNo('No %1 found matching "%2"', ImportType, ImportValue);
end;
exit(false);
end;
3. GetLastEntryIntFieldValue – The Time Saver
Need to get a field value from the last entry in a table? This method has you covered:
procedure GetLastEntryIntFieldValue(SourceRec: Variant; FieldNo: Integer): Integer
It’s optimized to ignore security filters and uses load fields for performance. Perfect for getting the next number in a sequence or checking the last posted document number.
Example: Getting Next Document Number with Error Handling
A more robust approach to document numbering:
local procedure GetNextDocumentNo(TableID: Integer; FieldNo: Integer): Code[20]
var
FindRecordMgt: Codeunit "Find Record Management";
RecRef: RecordRef;
LastDocNo: Integer;
NextDocNo: Code[20];
NoSeriesMgt: Codeunit NoSeriesManagement;
begin
RecRef.Open(TableID);
// Try to get the last document number
LastDocNo := FindRecordMgt.GetLastEntryIntFieldValue(RecRef, FieldNo);
if LastDocNo = 0 then begin
// No records found or field is not numeric
// Maybe use a number series instead
NextDocNo := NoSeriesMgt.GetNextNo('CUSTOM-DOC', WorkDate(), false);
end else begin
// Increment the last number
NextDocNo := Format(LastDocNo + 1);
end;
RecRef.Close();
exit(NextDocNo);
end;
Extending the Functionality
One of the coolest things about this codeunit is how extensible it is. Microsoft has built in integration events throughout the code, so you can:
- Add support for custom record types
- Modify search behavior for specific scenarios
- Add additional search fields
- Customize the similarity matching algorithm
For example, if you have a custom table type, you can use the OnAfterGetRecRefAndFieldsNoByType event to add support for it.
Common Pitfalls to Avoid
- Don’t assume you’ll always get exactly one result
- Remember that security filters can affect results
- Be careful with very short search strings – they might match too many records
- Test the similarity matching with your actual data – it might not work the same way in different languages
Wrapping Up
The Find Record Management codeunit is one of those hidden gems in Business Central that can dramatically improve your user experience with minimal effort. Instead of building complex search logic from scratch, you can leverage this battle-tested, optimized solution that handles edge cases you probably haven’t even thought of.
Next time you need to implement record searching in your Business Central application, give this Codeunit a try. Your users will thank you for the intelligent search behavior, and you’ll thank yourself for not having to write all that search logic from scratch.
The beauty of Business Central is that Microsoft has already solved many of the common development challenges we face. Sometimes the best code is the code you don’t have to write – you just need to know where to find the solution that already exists.
Subscribe to our email newsletter to get the latest posts delivered right to your email.


Comments