RecordInsertList & RecordSortedList in Dynamics 365 Finance & Operations
Question 23 — Batching inserts and holding in-memory record sets to cut database round trips.
Interview Question
RecordInsertList and RecordSortedList
classes in Dynamics 365 Finance & Operations? How do they improve performance, and how do they differ from each
other and from a set-based insert_recordset?
Model Answer (Short)
RecordInsertList is a system class that buffers multiple records and
inserts them into the database in as few round trips as possible — you add() records
in a loop and then call insertDatabase(). It is the go-to option when the target table's
insert() method is overridden (so you still want per-record logic) but you also want
batching. RecordSortedList is an in-memory, sorted collection of
records held in a defined order; it's used to pass a set of records around (e.g. to a form or dialog) rather than to
bulk-insert. In contrast, insert_recordset is a pure set-based SQL insert that skips
the insert() method entirely (unless it falls back).
Detailed Explanation
RecordInsertList
- Buffers records added via
add()and flushes them withinsertDatabase(). - Reduces AOS↔SQL round trips by sending records in packs.
- Still calls the table's overridden
insert()method (unless configured otherwise), so per-record logic runs. - Ideal when the
insert()method is overridden but you loop over many records.
RecordSortedList
- An in-memory collection that keeps records in a defined sort order.
- Used to hold and pass a set of records (e.g. selected grid rows to a dialog/form), not for bulk insert.
- Supports navigation methods to iterate the sorted set.
Prerequisites (Rule 5)
- Visual Studio with the Dynamics 365 developer tools.
- A custom model / package for your objects.
- A target table for the inserts (with or without an overridden
insert()). - A transaction scope (
ttsbegin/ttscommit) around the database insert.
Code Example — RecordInsertList
AbcStagingTable staging;
RecordInsertList insertList = new RecordInsertList(tableNum(AbcStagingTable));
ttsbegin;
for (int i = 1; i <= 1000; i++)
{
staging.clear();
staging.LineNum = i;
staging.Processed = NoYes::No;
insertList.add(staging); // buffered, not yet sent to SQL
}
insertList.insertDatabase(); // flush remaining records in few round trips
ttscommit;
RecordSortedList — build & iterate
CustTable custTable;
RecordSortedList sortedList = new RecordSortedList(tableNum(CustTable));
// Sort the in-memory set by AccountNum
sortedList.sortOrder(fieldNum(CustTable, AccountNum));
while select custTable
where custTable.Blocked == CustVendorBlocked::No
{
sortedList.ins(custTable); // add to the sorted in-memory list
}
// Navigate the sorted set
if (sortedList.first(custTable))
{
do
{
info(custTable.AccountNum);
}
while (sortedList.next(custTable));
}
Passing a RecordSortedList to a form
// A RecordSortedList can carry selected records to another form/dialog
RecordSortedList selected = new RecordSortedList(tableNum(SalesLine));
selected.sortOrder(fieldNum(SalesLine, LineNum));
// ... populate 'selected' from the caller's marked records ...
Args args = new Args();
args.caller(this);
args.object(selected); // hand the set to the called menu item/form
RecordInsertList vs. RecordSortedList vs. insert_recordset
| Aspect | RecordInsertList | RecordSortedList | insert_recordset |
|---|---|---|---|
| Purpose | Batched insert to DB | In-memory sorted set | Pure set-based SQL insert |
Calls table insert() |
Yes (per record) | N/A (no DB insert) | No (unless fallback) |
| Round trips | Few (packed) | None (memory) | Single statement |
| Typical use | Loop insert with overridden method | Pass/iterate records | Copy source→target in bulk |
Points the interviewer wants to hear
RecordInsertListbatches inserts to cut round trips while still callinginsert().- Use it when the table's
insert()is overridden but you insert many rows in a loop. RecordSortedListis an in-memory sorted collection, not a bulk-insert tool.insert_recordsetis fastest for pure copies but bypasses theinsert()method.- Always wrap the flush (
insertDatabase()) in a transaction.
Likely Follow-up Questions
- When would you choose
RecordInsertListoverinsert_recordset? - Does
RecordInsertListguarantee a single round trip? - What is
RecordSortedListtypically used for in forms? - How do you pass a set of selected records between forms?
Key Takeaway
Use RecordInsertList to batch inserts (few round trips, still runs
insert()) and RecordSortedList to hold and pass a
sorted in-memory set. Reach for insert_recordset only when a pure set-based copy
that skips insert() is acceptable.