Handling Multi-Type Notes with BLOB Fields in Business Central (Real-World Implementation)
Handling Multi-Type Notes with BLOB Fields in Business Central (Real-World Implementation)
Introduction
While working on an Issue Management module in Microsoft Dynamics 365 Business Central, I came across a scenario that looks simple on the surface—but becomes quite tricky when implemented:
How do you store multiple large notes (10k+ characters) for a single record, across different categories, while maintaining proper structure and performance?
This blog walks through the complete solution, including the challenges, debugging journey, and final working design.
Problem Statement
The requirement was to:
Create a system where a single Issue Card can have multiple notes
Notes should be categorized into:
Compliance
Root Cause
Corrective Action
Each category should have its own subpage (ListPart)
Notes should support large text (>10,000 characters)
Data should be stored line-wise
Challenges Faced
During implementation, several issues appeared:
Multiple subpages were used, but all pointed to the same table
Notes field was implemented as a BLOB (for large text support)
New lines were not getting created properly
"Line No." was always 0
Records were not inserting consistently
Users had to manually refresh or click Edit
Key Design Decisions
To solve this, the following architecture was implemented:
1. Table Design – "Issues Notes"
table 50226 "Issues Notes"
Fields:
Issue No. → Links to parent record
Issue Type → Differentiates subpages
Line No. → Unique identifier per line
Notes (BLOB) → Stores large text
Primary Key:
key(PK; "Issue No.", "Issue Type", "Line No.")
This ensures:
Data separation per Issue
Independent notes per type
Unique line-wise storage
2. Manual Line Numbering (OnInsert)
Instead of relying fully on UI behavior, line numbering was handled manually:
trigger OnInsert()
var
NotesRec: Record "Issues Notes";
begin
NotesRec.SetRange("Issue No.", Rec."Issue No.");
NotesRec.SetRange("Issue Type", Rec."Issue Type");
if NotesRec.FindLast() then
Rec."Line No." := NotesRec."Line No." + 10000
else
Rec."Line No." := 10000;
end;
Why this approach?
Works independently of page behavior
Gives full control over numbering
Ensures consistency across subpages
3. Subpage Design (ListPart)
page 50250 "Issue Notes"
Key Properties:
AutoSplitKey = true;
MultipleNewLines = true;
Even though manual numbering is used, these properties help maintain UI flexibility.
Creating New Lines via Action
Since direct editing of BLOB is not feasible, an action-based approach was used:
action(EditNotes)
Logic:
if Rec."Line No." = 0 then begin
Rec.Insert(true);
CurrPage.Update(true);
end else
CurrPage.SaveRecord();
Commit();
NotePage.SetRecord(Rec);
NotePage.RunModal();
This ensures:
New line is forcefully inserted
"Line No." is generated via OnInsert
Record exists before opening dialog
4. BLOB Handling via Dialog Page
Since BLOB fields cannot be edited directly:
page 50255 "Issue Notes Dialog"
Writing Data to BLOB
Rec.Notes.CreateOutStream(OutStream, TEXTENCODING::UTF8);
OutStream.WriteText(NewText);
Rec.Modify();
Reading Data from BLOB
Rec.CalcFields(Notes);
Rec.Notes.CreateInStream(InStream, TEXTENCODING::UTF8);
InStream.ReadText(Txt);
Why BLOB?
Supports very large text (200k+ characters)
Avoids limitations of Text fields
Efficient storage
5. Multiple Subpages in Main Page
On the Issue Card, multiple subpages were added:
part(ComplianceNotes; "Issue Notes")
SubPageLink = "Issue No." = field("Issue No");
SubPageView = where("Issue Type" = const("Compliance"));
Important Insight
SubPageView only filters records—it does NOT assign values.
So "Issue Type" must be handled carefully (either via logic or controlled insert)
6. End-to-End Flow
When user clicks Edit Notes:
Check if line exists
If not → Insert record
OnInsert generates "Line No."
Commit transaction
Open dialog page
User enters large text
Data saved to BLOB
Output
Final Outcome
After implementing the above:
New lines are created correctly
"Line No." increments properly
Each subpage works independently
Large notes are handled efficiently
No UI refresh issues
Clean and scalable design
Key Learnings
SubPageView ≠ Data assignment
BLOB requires stream-based handling
Always ensure record exists before opening modal pages
OnInsert is powerful for controlled numbering
Avoid mixing too much UI logic with data logic
Conclusion
This implementation demonstrates how a seemingly simple requirement—storing notes—can become complex when:
Data size is large
Multiple categories exist
UI interactions are involved
By combining:
Proper table design
Controlled insert logic
Dialog-based editing
we achieve a robust and scalable solution.