2.4 Adapting REFramework: Tabular Data, Collections & Linear Processes

Key Takeaways

  • Changing the transaction source means updating the TransactionItem type in Main.xaml and in the GetTransactionData, Process, and SetTransactionStatus arguments.

  • For tabular data, load the DataTable once into an In/Out argument and return Rows(in_TransactionNumber - 1), because TransactionNumber starts at 1 while rows are zero-based.

  • Returning Nothing from GetTransactionData.xaml is what ends the run through the No Data transition.

  • SetTransactionStatus.xaml calls Set Transaction Status only for QueueItem transactions, so non-queue projects need their own status record.

  • A linear process returns one item on the first cycle and Nothing on the second, and uses MaxRetryNumber for retries.

Last updated: September 2026

2.4 Adapting REFramework: Tabular Data, Collections & Linear Processes

Core Concept: The REFramework template assumes an Orchestrator queue, but the exam description expects you to adapt it in three other ways: a transactional project with tabular data (DataTable rows), a transactional project with a collection (a list of files, emails, or IDs), and a linear process that runs its business logic once. Every adaptation touches the same three places: the TransactionItem type, GetTransactionData.xaml, and the way the result is recorded.


Step 1: Change the TransactionItem Type Everywhere

TransactionItem is a variable in Main.xaml and an argument in several framework workflows. When you change its type, update all of them, or the project will not compile:

LocationNameChange it to (tabular example)
Main.xaml variablesTransactionItemSystem.Data.DataRow
GetTransactionData.xamlout_TransactionItemSystem.Data.DataRow
Process.xamlin_TransactionItemSystem.Data.DataRow
SetTransactionStatus.xamlin_TransactionItemSystem.Data.DataRow

For tabular data, also add a variable in Main.xaml, such as TransactionData of type DataTable, and pass it to GetTransactionData.xaml as an In/Out argument (io_TransactionData). The table is loaded once and then kept for every later cycle.


Step 2: Rewrite GetTransactionData.xaml

Tabular data (DataTable rows)

' GetTransactionData.xaml (tabular)
If in_TransactionNumber = 1 Then
    ' Read Range / Run Query once, store the result in io_TransactionData
End If

If in_TransactionNumber <= io_TransactionData.Rows.Count Then
    out_TransactionItem = io_TransactionData.Rows(in_TransactionNumber - 1)
Else
    out_TransactionItem = Nothing   ' no more rows: go to End Process
End If

Two details trip people up:

  • TransactionNumber starts at 1, but Rows is zero-based, so the index is in_TransactionNumber - 1.
  • Returning Nothing is what triggers the No Data transition to End Process. Forgetting the Else branch causes an IndexOutOfRangeException after the last row.

Loading the data only on the first cycle (or only when the table is Nothing) matters. Re-reading the Excel file on every cycle is slow and can pick up rows that changed during the run.

Collections (files, emails, IDs)

A collection works the same way with a different type. For a folder of PDFs, make TransactionItem a String (or FileInfo) and keep a String() array of paths:

If in_TransactionNumber = 1 Then io_FilePaths = Directory.GetFiles(in_Config("InputFolder").ToString, "*.pdf")
out_TransactionItem = If(in_TransactionNumber <= io_FilePaths.Length, io_FilePaths(in_TransactionNumber - 1), Nothing)

For mailboxes, a List(Of MailMessage) or an Integration Service email object plays the same role.

Linear process (run once)

A linear process, such as a nightly report download, has no records to loop over. Give it one "transaction" and then stop:

If in_TransactionNumber = 1 Then
    out_TransactionItem = "RunOnce"
Else
    out_TransactionItem = Nothing
End If

You keep the framework's benefits: configuration loading, clean initialization, the business versus system exception split, screenshots, and robot retries through MaxRetryNumber.


Step 3: Record the Outcome Without a Queue

SetTransactionStatus.xaml only calls the Set Transaction Status activity when the item is a QueueItem. The template checks with in_TransactionItem.GetType Is GetType(UiPath.Core.QueueItem) before calling it. For DataRows, files, or linear runs, that activity is skipped automatically, and the framework still does the following:

  • logs the outcome with the transaction log fields (status, number, ID, and the two extra fields),
  • increments io_TransactionNumber, or the retry counter for robot retries,
  • takes a screenshot and closes the applications after a System Exception.

Because there is no queue to show status, you need your own record: write a Status column back to the DataTable and save it at End Process, move processed files to Done or Error folders, or send a summary email. Set out_TransactionID, out_TransactionField1, and out_TransactionField2 in GetTransactionData.xaml (for example, the invoice number) so every log line identifies the record.


Retries Without a Queue

Without Orchestrator's queue retry, MaxRetryNumber on the Constants sheet is the retry mechanism. Set it above 0 (for example, 2). A System Exception then keeps the same TransactionNumber, returns through Initialization, and fetches the same row or file again. A business exception never retries and moves on to the next record.

ScenarioTransactionItem typeData loadedEnd conditionRetry setting
Queue performer (default)QueueItemGet Transaction Item on every cycleQueue empty or stop requestedQueue Auto Retry; MaxRetryNumber = 0
Excel or SQL rowsDataRowOnce, into io_TransactionDataTransactionNumber > row countMaxRetryNumber > 0
Folder of filesString or FileInfoOnce, into an arrayIndex past the array lengthMaxRetryNumber > 0
Linear runString or BooleanNot neededSecond cycle returns NothingMaxRetryNumber > 0 if a retry makes sense

Tip

A tabular performer cannot be scaled across several robots, because each robot would read the same file and process the same rows. When volume or parallelism matters, convert the source into a queue with a Dispatcher.

Test Your Knowledge

A developer adapts REFramework to process rows from an Excel file loaded into io_TransactionData. How should GetTransactionData.xaml set out_TransactionItem on each cycle?

A

Call Get Transaction Item and cast the returned QueueItem to a DataRow.

B

Add each row to a temporary queue with Add Queue Item and fetch it back.

C

If in_TransactionNumber is at most the row count, return io_TransactionData.Rows(in_TransactionNumber - 1); otherwise return Nothing.

D

Re-read the Excel file on every cycle and filter it by in_TransactionNumber.

Test Your Knowledge

In a REFramework project adapted to a folder of PDF files, what happens inside SetTransactionStatus.xaml when a file is processed successfully?

A

The template calls Set Transaction Status with Status Successful, which fails because there is no queue.

B

The template skips the Set Transaction Status activity because the item is not a QueueItem, logs the outcome with the transaction log fields, and increments the transaction number.

C

The template automatically moves the PDF to a Done folder.

D

The template converts the file into a queue item so Orchestrator can track it.

Test Your Knowledge

Why does a linear REFramework process usually keep MaxRetryNumber above 0?

A

Because Orchestrator queue retries are unavailable without a queue, so robot retries are the only way to retry the single run after a System Exception.

B

Because a linear process needs MaxRetryNumber to decide when to stop fetching data.

C

Because MaxRetryNumber must always match the queue Max # of retries value.

D

Because business exceptions are retried only when MaxRetryNumber is above 0.

Sections you finish are checked off in the contents.