<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[X++ DataStructures]]></title><description><![CDATA[X++ DataStructures]]></description><link>https://challafnods.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Fri, 09 Oct 2026 04:57:05 GMT</lastBuildDate><atom:link href="https://challafnods.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Mastering X++ Containers in D365 F&O]]></title><description><![CDATA[This blog explores how to leverage X++ containers in banking and financial scenarios with practical examples that you can implement in your own solutions. What Are X++ Containers?
What Are X++ Containers?
Containers in X++ are versatile data structur...]]></description><link>https://challafnods.hashnode.dev/mastering-x-containers-in-d365-fando</link><guid isPermaLink="true">https://challafnods.hashnode.dev/mastering-x-containers-in-d365-fando</guid><category><![CDATA[D365 X++]]></category><category><![CDATA[D365 F&O]]></category><dc:creator><![CDATA[Challa]]></dc:creator><pubDate>Wed, 14 May 2025 04:23:38 GMT</pubDate><content:encoded><![CDATA[<p>This blog explores how to leverage X++ containers in banking and financial scenarios with practical examples that you can implement in your own solutions. What Are X++ Containers?</p>
<h3 id="heading-what-are-x-containers">What Are X++ Containers?</h3>
<p>Containers in X++ are versatile data structures that can store multiple values of different types in a single variable. Unlike arrays or lists that typically store elements of the same type, containers can mix strings, integers, dates, and even record IDs in one collection.</p>
<p>Key characteristics:</p>
<ul>
<li><p>Heterogeneous storage (multiple data types)</p>
</li>
<li><p>Dynamic sizing (grow and shrink as needed)</p>
</li>
<li><p>One-based indexing (first element is at position 1)</p>
</li>
<li><p>Built-in manipulation functions with the "con" prefix</p>
</li>
</ul>
<h3 id="heading-internal-implementation-details">Internal Implementation Details</h3>
<ol>
<li><p><strong>Memory Management</strong>: X++ containers use a dynamically allocated memory block that grows as needed. When a container exceeds its current capacity, the runtime allocates a larger block and copies the existing elements.</p>
</li>
<li><p><strong>Type Handling</strong>: Containers maintain type information for each element. When you retrieve a value with <code>conPeek()</code>, the runtime performs an implicit type conversion if necessary.</p>
</li>
<li><p><strong>Serialization Support</strong>: Containers can be easily serialized and deserialized, making them ideal for storing in database fields or passing between tiers in the D365 architecture.</p>
</li>
<li><p><strong>Value Semantics</strong>: Containers use value semantics (not reference semantics), meaning when you assign one container to another, a complete copy is made:</p>
<pre><code class="lang-plaintext">  container c1 = [1, 2, 3];
    container c2 = c1;  // Creates a complete copy
    conPoke(c1, 1, 99); // Only affects c1, not c2
</code></pre>
<ol start="5">
<li><strong>AOT Representation</strong>: In X++ metadata, containers are represented using the <code>Array</code> type with special handling for heterogeneous contents.</li>
</ol>
</li>
</ol>
<h3 id="heading-example-banking-transaction-batch-processing">Example : Banking Transaction Batch Processing</h3>
<pre><code class="lang-plaintext">//Plz Treat this as Example Code , Not Production Standard

public void processBankTransactions(BankAccountTable _bankAccount)
{
    container transactionBatch;
    container currentTransaction;
    BankTransactionTable bankTrans;

    // Build a batch of pending transactions
    while select * from bankTrans
        where bankTrans.BankAccountId == _bankAccount.RecId &amp;&amp;
              bankTrans.Status == BankTransactionStatus::Pending
    {
        // Store each transaction as a container within our batch container
        currentTransaction = [bankTrans.RecId,          // Transaction ID
                             bankTrans.TransDate,       // Transaction date
                             bankTrans.Amount,          // Amount
                             bankTrans.TransactionType, // Type
                             bankTrans.Reference];      // Reference

        transactionBatch += currentTransaction;
    }

    // Process each transaction in the batch
    for (int i = 1; i &lt;= conLen(transactionBatch); i++)
    {
        currentTransaction = conPeek(transactionBatch, i);

        try
        {
            this.processTransaction(currentTransaction);
            this.updateTransactionStatus(conPeek(currentTransaction, 1), 
                                        BankTransactionStatus::Processed);
        }
        catch (Exception::Error)
        {
            this.updateTransactionStatus(conPeek(currentTransaction, 1),
                                        BankTransactionStatus::Error);
            // Log error details
        }
    }
}
</code></pre>
<h3 id="heading-another-example-bank-reconciliation-helper">Another Example : Bank Reconciliation Helper</h3>
<p>When reconciling bank statements, you often need to temporarily store matches between system records and bank statement lines:</p>
<pre><code class="lang-plaintext">//Plz Treat this as Example Code , Not Production Standard
public container findPotentialMatches(BankStatementLine _statementLine)
{
    container matches;
    container matchDetails;
    LedgerJournalTrans journalTrans;
    BankAccountTrans bankTrans;

    // Look for matches in journal entries
    while select * from journalTrans
        where journalTrans.AccountType == LedgerJournalACType::Bank &amp;&amp;
              journalTrans.Account == _statementLine.BankAccountId &amp;&amp;
              journalTrans.AmountCurDebit == _statementLine.Amount &amp;&amp;
              journalTrans.TransDate == _statementLine.TransactionDate
    {
        matchDetails = ['JournalEntry',             // Match type
                        journalTrans.RecId,         // Record ID
                        journalTrans.Voucher,       // Voucher
                        journalTrans.AmountCurDebit,// Amount
                        journalTrans.TransDate];    // Date

        matches += matchDetails;
    }

    // Look for matches in bank transactions
    while select * from bankTrans
        where bankTrans.BankAccountId == _statementLine.BankAccountId &amp;&amp;
              bankTrans.Amount == _statementLine.Amount &amp;&amp;
              bankTrans.ValueDate == _statementLine.TransactionDate
    {
        matchDetails = ['BankTransaction',         // Match type
                        bankTrans.RecId,           // Record ID
                        bankTrans.Reference,       // Reference
                        bankTrans.Amount,          // Amount
                        bankTrans.ValueDate];      // Date

        matches += matchDetails;
    }

    return matches;
}
</code></pre>
<h3 id="heading-advanced-container-techniques-in-banking-applications">Advanced Container Techniques in Banking Applications</h3>
<p>Beyond the basic examples, here are some advanced techniques that can take your container usage to the next level in banking applications:</p>
<h3 id="heading-1-functional-container-operations">1. Functional Container Operations</h3>
<p>You can implement functional programming techniques with containers:</p>
<pre><code class="lang-plaintext">//Plz Treat this as Example Code , Not Production Standard

public container filterContainer(container _source, IdentifierName _predicateFunctionName)
{
    container result;
    DictClass dictClass = new DictClass(0); // Properly initialize with an iterator ID

    for (int i = 1; i &lt;= conLen(_source); i++)
    {
        // Call the predicate function to determine if element should be kept
        if (dictClass.callStatic(_predicateFunctionName, _source, i))
        {
            result += conPeek(_source, i);
        }
    }

    return result;
}

// Example usage for transaction filtering
public static boolean isHighValueTransaction(container _transactions, int _index)
{
    container transaction = conPeek(_transactions, _index);
    real amount = conPeek(transaction, 3);

    return amount &gt; 10000; // Consider transactions over 10,000 as high-value
}

// Usage in code
container highValueTransactions = filterContainer(transactionBatch, 
                                                 identifierStr(isHighValueTransaction));
</code></pre>
<h3 id="heading-performance-analysis-big-o-for-x-containers">Performance Analysis: Big O for X++ Containers</h3>
<p>Understanding the time complexity of container operations is crucial when working with large datasets in banking applications. Here's a comprehensive analysis of X++ container operations:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Operation</td><td>Function</td><td>Time Complexity</td><td>Description</td></tr>
</thead>
<tbody>
<tr>
<td>Access</td><td><code>conPeek(container, index)</code></td><td>O(1)</td><td>Direct access by index is constant time</td></tr>
<tr>
<td>Update</td><td><code>conPoke(container, index, value)</code></td><td>O(1)</td><td>Updating an existing element is constant time</td></tr>
<tr>
<td>Length</td><td><code>conLen(container)</code></td><td>O(1)</td><td>Getting container size is constant time</td></tr>
<tr>
<td>Add</td><td><code>container += value</code></td><td>O(1)*</td><td>Adding to the end of a container is amortized constant time</td></tr>
</tbody>
</table>
</div><p><em>\</em>Note: While appending is O(1) amortized, individual operations may occasionally trigger a reallocation, which is O(n).*</p>
<h3 id="heading-search-operations">Search Operations</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Operation</td><td>Function</td><td>Time Complexity</td><td>Description</td></tr>
</thead>
<tbody>
<tr>
<td>Find</td><td><code>conFind(container, value)</code></td><td>O(n)</td><td>Linear search through all elements</td></tr>
<tr>
<td>Find with Predicate</td><td>Custom loop with condition</td><td>O(n)</td><td>Must check each element until match found</td></tr>
</tbody>
</table>
</div><h3 id="heading-modification-operations">Modification Operations</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Operation</td><td>Function</td><td>Time Complexity</td><td>Description</td></tr>
</thead>
<tbody>
<tr>
<td>Insert</td><td><code>conIns(container, index, value)</code></td><td>O(n)</td><td>Requires shifting elements after insertion point</td></tr>
<tr>
<td>Delete</td><td><code>conDel(container, index)</code></td><td>O(n)</td><td>Requires shifting elements after deletion point</td></tr>
<tr>
<td>Concatenate</td><td><code>conCat(container1, container2)</code></td><td>O(n)</td><td>Where n is the size of the second container</td></tr>
</tbody>
</table>
</div><h3 id="heading-memory-complexity">Memory Complexity</h3>
<p>Memory usage is another critical aspect when dealing with financial data:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Operation</td><td>Memory Overhead</td><td>Notes</td></tr>
</thead>
<tbody>
<tr>
<td>Container Creation</td><td>O(1)</td><td>Initial allocation</td></tr>
<tr>
<td>Element Addition</td><td>O(n) in worst case</td><td>When capacity is exceeded, reallocation occurs</td></tr>
<tr>
<td>Container Copy</td><td>O(n)</td><td>Full copy is made</td></tr>
<tr>
<td>Nested Containers</td><td>O(sum of all elements)</td><td>Each container has its own allocation</td></tr>
</tbody>
</table>
</div><h4 id="heading-large-dataset-considerations">Large Dataset Considerations</h4>
<p>For very large datasets (e.g., processing thousands of bank transactions), consider these optimizations:</p>
<ul>
<li><p><strong>Batch size control</strong>: Limit container sizes to avoid memory issues</p>
</li>
<li><p><strong>Database filtering</strong>: Filter data at the database level before adding to containers</p>
</li>
<li><p><strong>Selective storage</strong>: Store only necessary fields in containers</p>
</li>
<li><p><strong>Memory management</strong>: Clear containers when no longer needed:</p>
<p>  <code>container myContainer; // ... operations ... myContainer = []; // Clear container</code></p>
<h3 id="heading-comparison-with-other-x-collections">Comparison with Other X++ Collections</h3>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747196492544/74944cec-db1e-43b1-b42d-2018f8bb3594.png" alt /></p>
<h3 id="heading-ia"> </h3>
</li>
</ul>
<p>Best Practices for X++ Containers</p>
<ol>
<li><p><strong>Document container structure</strong>: Always document what each position in your container represents.</p>
</li>
<li><p><strong>Consider type safety</strong>: For complex scenarios, weigh containers against structured types like classes.</p>
</li>
<li><p><strong>Use constants for indexes</strong>: Define constants for container positions to avoid "magic numbers":<br /> <code>#define.CUST_PROFILE_ACCOUNT(1)</code><br /> <code>#define.CUST_PROFILE_NAME(2)</code><br /> <code>#define.CUST_PROFILE_BANK_ACCOUNT(3)</code><br /> <code>// Usage:</code><br /> <code>str accountNum = conPeek(profile, #CUST_PROFILE_ACCOUNT);</code></p>
</li>
<li><p><strong>Validate containers</strong>: Check container length before accessing elements.</p>
</li>
<li><p><strong>Nested containers</strong>: For complex data, consider containers within containers as seen in the transaction example.</p>
</li>
<li><p><strong>Performance monitoring</strong>: For large banking operations, monitor memory consumption and processing time when using large containers.</p>
</li>
<li><p><strong>Boundary checking</strong>: Always check container boundaries before accessing elements:<br /> <code>if (conLen(container) &gt;= index) { value = conPeek(container, index); }</code></p>
</li>
<li><p><strong>Container reuse</strong>: Consider clearing and reusing containers for repetitive operations to reduce memory allocations:<br /> <code>container reusableContainer;</code></p>
<p> <code>// In a loop   reusableContainer = [];   // Clear before reuse   // Add new data...</code></p>
</li>
<li><p><strong>Encapsulate container operations</strong>: Create utility methods for common container operations to improve code readability and maintainability.</p>
</li>
<li><p><strong>Balance with other data structures</strong>: Use the right tool for the job—containers for heterogeneous collections, Lists for homogeneous collections with frequent insertions, Maps for key-value lookups.</p>
</li>
</ol>
<h3 id="heading-conclusion">Conclusion</h3>
<p>X++ containers provide a flexible and powerful way to handle diverse data types in Dynamics 365 F&amp;O banking modules. They shine in scenarios involving temporary storage, parameter passing, and working with heterogeneous data. While they shouldn't replace proper class design for complex business objects, they offer an elegant solution for many everyday development challenges.  </p>
<p>Remember that containers are a tool in your arsenal—not a silver bullet. When used appropriately, they can significantly improve code readability and maintainability while maintaining good performance. But they should be complemented with proper object-oriented design for complex domain models and data structures.</p>
]]></content:encoded></item><item><title><![CDATA[X++ Data Structures for C# Developers: Bridging the Gap]]></title><description><![CDATA[From Web APIs to ERP : A Developers Journey
As someone who just recently started in the Dynamics 365 F&O space after spending many years in the world of .NET APIs and Web development, my first encounter with X++ felt like landing on an alien planet. ...]]></description><link>https://challafnods.hashnode.dev/x-data-structures-for-c-developers-bridging-the-gap</link><guid isPermaLink="true">https://challafnods.hashnode.dev/x-data-structures-for-c-developers-bridging-the-gap</guid><category><![CDATA[X++ Datastructures, ]]></category><category><![CDATA[Dynamics F&O]]></category><category><![CDATA[X++ for C# Devs]]></category><category><![CDATA[dynamics 365 finance]]></category><dc:creator><![CDATA[Challa]]></dc:creator><pubDate>Wed, 26 Mar 2025 02:15:05 GMT</pubDate><content:encoded><![CDATA[<h2 id="heading-from-web-apis-to-erp-a-developers-journey">From Web APIs to ERP : A Developers Journey</h2>
<p>As someone who just recently started in the Dynamics 365 F&amp;O space after spending many years in the world of .NET APIs and Web development, my first encounter with X++ felt like landing on an alien planet. The syntax looked <em>almost</em> familiar -- yes, there were curly braces and semicolons -- but the way data structures worked? That was a whole different story.</p>
<p>“Where is the List equivalent in this language?" I remember asking during my first week. "How is it possible to mix different data types in the same collection without type constraints?</p>
<p>If you're a C# developer who's been thrown into the X++ world (or just starting like me), I understand your confusion. This post is everything I wish someone had told me when I first made the transition, written while the struggles and discoveries are still fresh in my mind.</p>
<h3 id="heading-understanding-the-x-data-access-architecture">Understanding the X++ Data Access Architecture</h3>
<p>When working with Dynamics 365 F&amp;O, you're dealing with a layered architecture designed specifically for enterprise resource planning (ERP) systems. Unlike the web APIs I was used to building, X++ code operates within the Application Object Server (AOS), which mediates between the user interface and the database.</p>
<p>Here's the full picture of how it all fits together:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742913572323/d336c767-d703-4a9c-a2cd-86d360a2ab1a.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-try-this-now-explore-your-environment">Try This Now: Explore Your Environment</h3>
<p>If you're new to D365 F&amp;O, take a moment to orient yourself:</p>
<ol>
<li><p><em>Open Visual Studio with your D365 F&amp;O development environment</em></p>
</li>
<li><p><em>Navigate to AOT &gt; Jobs</em></p>
</li>
<li><p><em>Create a new job called "ExploreDataStructures"</em></p>
</li>
<li><p><em>Add this simple code to print out the type of architecture you're working with</em></p>
</li>
<li><pre><code class="lang-csharp">       <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ExploreDataStructures</span>(<span class="hljs-params">Args _args</span>)</span>
       {
           info(<span class="hljs-string">"I'm running in: "</span> + Microsoft.Dynamics.AX.Metadata.Core.xppObject.getApplicationContext().getEnvironment());
           info(<span class="hljs-string">"Available to me are various X++ data structures!"</span>);
       }
</code></pre>
<p> This simple exercise helps establish where your code will execute and reinforces that you're in a different world than typical C# applications.</p>
</li>
</ol>
<h3 id="heading-x-data-structures-the-building-blocks">X++ Data Structures: The Building Blocks</h3>
<details><summary>Containers: The Swiss Army Knife</summary><div data-type="detailsContent">In the C# world, you're used to strongly-typed collections. In X++, the container is a flexible data structure that can hold multiple data types at once.</div></details>

<p>Try This Now: Your First X++ Container</p>
<p>X++ container with mixed types container <code>myContainer = ['String value', 123, true];</code></p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ContainerExperiment</span>(<span class="hljs-params">Args _args</span>)</span>
{
    container myFirstContainer = [<span class="hljs-string">'Customer'</span>, <span class="hljs-number">1001</span>, <span class="hljs-literal">true</span>];

    <span class="hljs-comment">// Access elements (notice the 1-based indexing!)</span>
    info(conPeek(myFirstContainer, <span class="hljs-number">1</span>)); <span class="hljs-comment">// Prints "Customer"</span>

    <span class="hljs-comment">// Add a new element</span>
    myFirstContainer += <span class="hljs-string">"New Value"</span>;
    (conLen(myFirstContainer)); <span class="hljs-comment">// Prints 4</span>

    <span class="hljs-comment">// What happens if we try to mix operations?</span>
    <span class="hljs-comment">// Uncomment to see the error:</span>
    <span class="hljs-comment">// int result = conPeek(myFirstContainer, 1) + conPeek(myFirstContainer, 2);</span>
}
</code></pre>
<p>What happened when you ran this? Did you notice how X++ handles the mixed types?</p>
<p><em>A Bit More Concrete Scenario</em></p>
<pre><code class="lang-csharp"><span class="hljs-comment">//Simplified Example Treat them as Mental Models,In Prod there are various Other considerations to be made</span>


<span class="hljs-comment">// Prepares reconciliation parameters for a bank statement import</span>
<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">SetupBankReconciliationParameters</span>(<span class="hljs-params">Args _args</span>)</span>
{
    <span class="hljs-comment">// Container holding mixed types for reconciliation settings</span>
    <span class="hljs-comment">// [AccountID, ToleranceAmount, AutoMatchEnabled, MatchingPeriodDays]</span>
    container reconcParams;
    str bankAccountId = <span class="hljs-string">'MAIN001'</span>;

    <span class="hljs-comment">// Create container with different parameter types</span>
    reconcParams = [
        bankAccountId,          <span class="hljs-comment">// String: Bank account ID</span>
        <span class="hljs-number">10.00</span>,                  <span class="hljs-comment">// Real: Tolerance amount for matching</span>
        <span class="hljs-literal">true</span>,                   <span class="hljs-comment">// Boolean: Enable automatic matching</span>
        <span class="hljs-number">30</span>                      <span class="hljs-comment">// Integer: Days to look back for matching</span>
    ];

    <span class="hljs-comment">// Display the parameters</span>
    info(<span class="hljs-string">"Bank Reconciliation Parameters:"</span>);
    info(strFmt(<span class="hljs-string">"Account: %1"</span>, conPeek(reconcParams, <span class="hljs-number">1</span>)));
    info(strFmt(<span class="hljs-string">"Tolerance Amount: $%1"</span>, conPeek(reconcParams, <span class="hljs-number">2</span>)));
    info(strFmt(<span class="hljs-string">"Auto-Matching: %1"</span>, conPeek(reconcParams, <span class="hljs-number">3</span>) ? <span class="hljs-string">"Enabled"</span> : <span class="hljs-string">"Disabled"</span>));
    info(strFmt(<span class="hljs-string">"Matching Period: %1 days"</span>, conPeek(reconcParams, <span class="hljs-number">4</span>)));

    <span class="hljs-comment">// Pass parameters to the reconciliation process</span>
    <span class="hljs-keyword">if</span> (conPeek(reconcParams, <span class="hljs-number">3</span>)) <span class="hljs-comment">// If auto-matching is enabled</span>
    {
        info(<span class="hljs-string">"Starting automatic reconciliation process..."</span>);
        runBankReconciliation(reconcParams);
    }
}

<span class="hljs-comment"><span class="hljs-doctag">///</span> Simulates running the bank reconciliation process</span>

<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">runBankReconciliation</span>(<span class="hljs-params">container _params</span>)</span>
{
    <span class="hljs-comment">// In a real system, this would use the parameters to</span>
    <span class="hljs-comment">// perform reconciliation between bank statements and ledger</span>
    info(strFmt(<span class="hljs-string">"Reconciling account %1 with $%2 tolerance for the past %3 days"</span>,
        conPeek(_params, <span class="hljs-number">1</span>),
        conPeek(_params, <span class="hljs-number">2</span>),
        conPeek(_params, <span class="hljs-number">4</span>)));
}
</code></pre>
<details><summary>Lists: The Ordered Collection</summary><div data-type="detailsContent">In C#, you'd reach for <code>List&lt;T&gt;</code>. In X++, there's the List class, which maintains items in the order you add them.</div></details>

<p>/X++ List List <code>myList = new List(Types::String); myList.addEnd("First item"); myList.addEnd("Second item");</code></p>
<p>Try This Now: Working with Lists</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ListExperiment</span>(<span class="hljs-params">Args _args</span>)</span>
{
    List nameList = <span class="hljs-keyword">new</span> List(Types::String);
    nameList.addEnd(<span class="hljs-string">"Alice"</span>);
    nameList.addEnd(<span class="hljs-string">"Dyamics"</span>);
    nameList.addEnd(<span class="hljs-string">"FnO"</span>);

    <span class="hljs-comment">// Lists have iterators</span>
    ListIterator iterator = <span class="hljs-keyword">new</span> ListIterator(nameList);

    <span class="hljs-keyword">while</span> (iterator.more())
    {
        info(iterator.<span class="hljs-keyword">value</span>());
        iterator.next();
    }
}
</code></pre>
<p><em>A Bit More Concrete Scenario</em></p>
<pre><code class="lang-csharp"><span class="hljs-comment">//Simplified Example Treat them as Mental Models,In Prod there are various Other considerations to be made</span>


<span class="hljs-comment">//Generates a list of bank accounts requiring review based on last activity date</span>
<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">FindInactiveBankAccounts</span>(<span class="hljs-params">Args _args</span>)</span>
{
    BankAccountTable bankAccount;
    List accountsToReview = <span class="hljs-keyword">new</span> List(Types::Record);
    ListIterator iterator;
    date reviewThreshold = systemDateGet() - <span class="hljs-number">90</span>; <span class="hljs-comment">// Accounts inactive for 90+ days</span>

    <span class="hljs-comment">// Find accounts with no recent activity</span>
    <span class="hljs-keyword">while</span> <span class="hljs-keyword">select</span> bankAccount
        <span class="hljs-keyword">where</span> bankAccount.LastActivity &lt; reviewThreshold &amp;&amp;
              bankAccount.AccountStatus == BankAccountStatus::Active
    {
        <span class="hljs-comment">// Add accounts requiring review to our list</span>
        accountsToReview.addEnd(bankAccount);
    }

    <span class="hljs-comment">// Process the list of accounts needing review</span>
    info(strFmt(<span class="hljs-string">"Found %1 bank accounts requiring review"</span>, accountsToReview.elements()));

    iterator = <span class="hljs-keyword">new</span> ListIterator(accountsToReview);
    <span class="hljs-keyword">while</span> (iterator.more())
    {
        bankAccount = iterator.<span class="hljs-keyword">value</span>();
        info(strFmt(<span class="hljs-string">"Account %1 (%2) - Last activity: %3"</span>, 
                   bankAccount.BankAccountId,
                   bankAccount.Name,
                   bankAccount.LastActivity));
        iterator.next();
    }
}
</code></pre>
<details><summary>Maps: The Key-Value Store</summary><div data-type="detailsContent">If you're used to <code>Dictionary&lt;K,V&gt;</code> in C#, you'll work with Map in X++</div></details>

<p>X++ Map <code>Map customerMap = new Map(Types::String, Types::Integer); customerMap.insert("CUST001", 1001); customerMap.insert("CUST002", 1002);</code></p>
<p><strong>Building a Customer Map</strong></p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">MapExperiment</span>(<span class="hljs-params">Args _args</span>)</span>
{
    <span class="hljs-comment">// Create a map of customer IDs to credit limits</span>
    Map creditLimitMap = <span class="hljs-keyword">new</span> Map(Types::String, Types::Real);

    <span class="hljs-comment">// Add some customers</span>
    creditLimitMap.insert(<span class="hljs-string">"CUST001"</span>, <span class="hljs-number">5000.00</span>);
    creditLimitMap.insert(<span class="hljs-string">"CUST002"</span>, <span class="hljs-number">10000.00</span>);

    <span class="hljs-comment">// Look up a credit limit</span>
    print(<span class="hljs-string">"Credit limit for CUST001: "</span> + 
        any2str(creditLimitMap.lookup(<span class="hljs-string">"CUST001"</span>)));

    <span class="hljs-comment">// Update a value</span>
    creditLimitMap.insert(<span class="hljs-string">"CUST001"</span>, <span class="hljs-number">7500.00</span>);
    print(<span class="hljs-string">"New credit limit for CUST001: "</span> + 
        any2str(creditLimitMap.lookup(<span class="hljs-string">"CUST001"</span>)));
}
</code></pre>
<p>A Bit More Concrete Scenario</p>
<p>Imagine a Scenario where you want to build a quick in-memory lookup of <strong>BankAccountId → CurrentBalance</strong>, so you can:</p>
<ul>
<li><p>Quickly retrieve balances for processing,</p>
</li>
<li><p>Compare multiple accounts,</p>
</li>
<li><p>Avoid repeated queries to the database.</p>
</li>
<li><pre><code class="lang-csharp">  <span class="hljs-comment">//Simplified Example Treat them as Mental Models,In Prod there are various Other considerations to be made</span>
  <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Map_BankAccountsBalances</span>(<span class="hljs-params">Args _args</span>)</span>
  {
      Map bankBalanceMap = <span class="hljs-keyword">new</span> Map(Types::String, Types::Real); <span class="hljs-comment">// BankAccountId → Balance</span>
      BankAccountTable bankAccount;
      BankAccountTrans bankTrans;
      AmountCur balance;

      <span class="hljs-comment">// 1. Loop through bank accounts</span>
      <span class="hljs-keyword">while</span> <span class="hljs-keyword">select</span> bankAccount
      {
          <span class="hljs-comment">// 2. Calculate balance (simplified logic: sum of transactions)</span>
          balance = <span class="hljs-number">0</span>;
          <span class="hljs-function"><span class="hljs-keyword">while</span> <span class="hljs-keyword">select</span> <span class="hljs-title">sum</span>(<span class="hljs-params">AmountCur</span>) <span class="hljs-keyword">from</span> bankTrans
              <span class="hljs-keyword">where</span> bankTrans.BankAccountID</span> == bankAccount.BankAccountId
          {
              balance = bankTrans.AmountCur;
          }

          <span class="hljs-comment">// 3. Add to Map</span>
          bankBalanceMap.insert(bankAccount.BankAccountId, balance);
      }

      <span class="hljs-comment">// 4. Iterate and display</span>
      MapEnumerator mapEnum = bankBalanceMap.getEnumerator();
      <span class="hljs-keyword">while</span> (mapEnum.moveNext())
      {
          str bankId = mapEnum.currentKey();
          real bal   = mapEnum.currentValue();
          info(strFmt(<span class="hljs-string">"Bank Account: %1 | Balance: %2"</span>, bankId, bal));
      }
  }
</code></pre>
</li>
<li><h2 id="heading-database-related-structures">Database-Related Structures</h2>
</li>
</ul>
<p>This is where X++ really differs from C# and web development. Instead of ORM frameworks like Entity Framework, X++ provides specialized structures for database operations:</p>
<details><summary>RecordSortedList: For Sorted In-Memory Records</summary><div data-type="detailsContent"><strong>A</strong> specialized X++ object that holds records in memory according to a specified sort order. This is especially useful if you need to programmatically build up a list of records with a defined sort sequence</div></details>

<pre><code class="lang-csharp"><span class="hljs-comment">// Sorting customers by name</span>
RecordSortedList sortedCustomers = <span class="hljs-keyword">new</span> RecordSortedList(tableNum(CustTable));
sortedCustomers.addSortField(fieldNum(CustTable, Name), SortOrder::Ascending);
</code></pre>
<p>A Bit More Concrete Scenario</p>
<pre><code class="lang-csharp"><span class="hljs-comment"><span class="hljs-doctag">///</span>/ Inserts multiple bank accounts in bulk for better performance</span>
<span class="hljs-comment">// A Mental Model for the data structure - </span>
<span class="hljs-comment">//In Production code you would want to Optimize for </span>
    <span class="hljs-comment">//1.  batch processing to handle larger datasets for timeout handing </span>
    <span class="hljs-comment">//2. Err Handling  </span>
    <span class="hljs-comment">//etc</span>

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">insertCustomersBulk</span>(<span class="hljs-params"></span>)</span>
{
    RecordInsertList recordInsertList;
    CustTable        custTable;
    <span class="hljs-keyword">int</span>              i;

    <span class="hljs-comment">// 1. Create a new RecordInsertList for CustTable</span>
    recordInsertList = <span class="hljs-keyword">new</span> RecordInsertList(tableNum(CustTable));

    <span class="hljs-comment">// 2. Loop and create multiple new records</span>
    <span class="hljs-keyword">for</span> (i = <span class="hljs-number">1</span>; i &lt;= <span class="hljs-number">5</span>; i++)
    {
        custTable.clear();
        custTable.AccountNum = strFmt(<span class="hljs-string">"NEWACC%1"</span>, i);
        custTable.Name       = strFmt(<span class="hljs-string">"New Customer %1"</span>, i);
        <span class="hljs-comment">// ... assign other fields as necessary</span>

        <span class="hljs-comment">// 3. Add the newly populated record to the RecordInsertList</span>
        recordInsertList.<span class="hljs-keyword">add</span>(custTable);
    }

    <span class="hljs-comment">// 4. Commit (bulk insert) all records to the database</span>
    ttsbegin;
    recordInsertList.insertDatabase();
    ttscommit;
}
</code></pre>
<details><summary>RecordSortedList: For Sorted In-Memory Records</summary><div data-type="detailsContent"><strong>A</strong> specialized X++ object that holds records in memory according to a specified sort order. This is especially useful if you need to programmatically build up a list of records with a defined sort sequence</div></details>

<p>Sorting customers by name<br /><code>RecordSortedList sortedCustomers = new RecordSortedList(tableNum(CustTable)); sortedCustomers.addSortField(fieldNum(CustTable, Name), SortOrder::Ascending);</code></p>
<p><em>A Bit More Concrete Scenario :</em> In-Memory Record Sorting</p>
<pre><code class="lang-csharp"><span class="hljs-comment">//Simplified Example Treat them as Mental Models,In Prod there are various Other considerations to be made</span>

<span class="hljs-comment">//Using RecordSortedList with BankAccountTable</span>
<span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">InMemorySortingExample</span>(<span class="hljs-params">Args _args</span>)</span>
{
    <span class="hljs-comment">// Create a sorted list of bank accounts by name</span>
    RecordSortedList sortedBankAccounts = <span class="hljs-keyword">new</span> RecordSortedList(tableNum(BankAccountTable));
    sortedBankAccounts.addSortField(fieldNum(BankAccountTable, Name), SortOrder::Ascending);

    BankAccountTable bankAccount;
    <span class="hljs-keyword">int</span> count = <span class="hljs-number">0</span>;

    <span class="hljs-keyword">while</span> <span class="hljs-keyword">select</span> bankAccount
    {
        <span class="hljs-keyword">if</span> (count++ &gt;= <span class="hljs-number">10</span>)
            <span class="hljs-keyword">break</span>;

        sortedBankAccounts.<span class="hljs-keyword">add</span>(bankAccount);
    }

    <span class="hljs-comment">// Now iterate through the sorted bank accounts</span>
    BankAccountTable sortedAcct;
    info(<span class="hljs-string">"Bank accounts sorted by name:"</span>);

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">1</span>; i &lt;= sortedBankAccounts.elements(); i++)
    {
        sortedAcct = sortedBankAccounts.getRecord(i);
        info(strFmt(<span class="hljs-string">"%1. %2"</span>, i, sortedAcct.Name));
    }
}
</code></pre>
<p><strong>Points to Ponder</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742912722422/65a74bd8-3fcd-4029-a457-bc05cc2d10d2.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-x-vs-c-side-by-side-visual-comparison">X++ vs. C# Side-by-Side: Visual Comparison</h3>
<p>To help you visualize the differences, here's a side-by-side comparison of common operations:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742954184875/677116a1-af04-4e43-9b8d-4a88811ed4b8.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-common-pitfalls-when-transitioning-from-c-to-x">Common Pitfalls When Transitioning from C# to X++</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742913133261/f3854013-e07a-4592-83d2-b21cb52423c5.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>As I continue learning my way through the X++ landscape, I'm discovering new patterns and practices every day. This post captures my understanding at this point in my journey, and I'll be sharing new insights as I grow more comfortable with Dynamics 365 F&amp;O development.</p>
<p>If you're also new to this world, I'd love to hear about your experiences and discoveries in the comments. And if you're a seasoned X++ developer who spotted something I've misunderstood, I welcome your gentle corrections -- we're all learning together!</p>
<p>Join me next week when I dive deeper into containers and how they compare to the C# collections I used to rely on. Until then, happy coding in whatever syntax life throws your way!</p>
<p>✨Happy <code>Coding!</code></p>
<hr />
]]></content:encoded></item></channel></rss>