Improvements on the global methods buf2con and con2buf in Microsoft Dynamics AX 2012

The global methods buf2con and con2buf are used on X++ to convert table buffers into containers and vice versa. New functionality has been added to these methods and they had been improved to be much faster than their implementation on previous versions of AX.

On Microsoft Dynamics AX 2012, a table buffer is converted into a container by packing the values of its fields into a single blob and then it is stored as one element inside a container. This process is much faster than previous versions of AX where each field was store individually inside the container. Note that the methods buf2con and con2buf create exact copies of the table buffers; they copy all fields including the system fields and flags.

void example()
{
    TableBuffer tableBuffer;
    TableBuffer tableBufferCopy;
    container packedTable;   

    ttsBegin;   

    tableBuffer.Field1 = 'example';
    tableBuffer.insert();

    ttsCommit;

    // pack
packedTable = buf2Con(tableBuffer);

    // unpack in a different table buffer
tableBufferCopy = con2Buf(packedTable);

    if (tableBufferCopy.Field1 == tableBuffer.Field1)
    {
        info('Values are equal');       
    }
}

The method buf2con has a new boolean parameter, _packOrigBuffer, which allows the developer to control whether or not the committed values of the fields would be packed. Packing the committed values might be required by the business logic, if this is the case, then set the _packOrigBuffer parameter to true, otherwise use a false to avoid packing the committed values and keep the container’s size as small as possible and speed up its transmission across the network. By default this parameter is set to false and only the new values of the fields (uncommitted values) are packed.

 

void examplePackCommittedValues()
{
    TableBuffer tableBuffer;
    TableBuffer tableBufferCopy;
    container packedTable;   

    ttsBegin;

    tableBuffer.Field1 = 'previous value';
    tableBuffer.insert();

    ttsCommit;

    tableBuffer.Field1 = 'new Value';

    // include the committed values
packedTable = buf2Con(tableBuffer, true);

    tableBufferCopy = con2buf(packedTable);

    if (tableBufferCopy.Field1 == tableBuffer.Field1 &&
       tableBufferCopy.orig().Field1 == tableBuffer.orig().Field1)
    {
        info('The new values and committed values are the same');
    }
}

 

Converting table buffers into containers is very useful when the table buffer needs to be sent across different tiers, for example between client and server. Sending a container is better than sending a table buffer because containers are passed by value and table buffers are passed by reference. Passing objects by reference across different tiers causes a high number of RPC and degrades the performance of your application. Referencing objects that were created on a different tier will cause an RPC every time the other tier invokes one the instance methods of the remote object:

void clientMethod()
{
    TableBuffer tableBuffer;

    tableBuffer.Field1 = 'Buffer on client';
    tableBuffer.insert();

    // pass the table buffer to a server method
Example::serverMethodUsingTableBuffer (tableBuffer);                           
}

// Method receiving a table buffer by reference
public static server void serverMethodUsingTableBuffer(TableBuffer clientTableBuffer)
{   
    // referencing the client object from the server

// RPC to client
clientTableBuffer.method1();

    // RPC to client
clientTableBuffer.method2();

    // RPC to client
clientTableBuffer.method3();

    . . .   
}

 

Using buf2con to pack the table buffer before sending it and using con2buf to unpack it avoids any callback by creating local copies of the table buffers and therefor improving performance:

void clientMethod()
{
    TableBuffer tableBuffer;
    container packedTable;   
    container packedTableNewState;

    tableBuffer.Field1 = 'Buffer on client';
    tableBuffer.insert();

    packedTable = buf2Con(tableBuffer);

    // pass the container to the server method, the server returns another container
packedTableNewState = Example::serverMethodUsingContainer (packedTable);                   

    // re-instantiate the table buffer with the container returned by the server
tableBuffer = con2Buf(packedTableNewState);
}

// Method receiving the container by value
public static server container serverMethodUsingContainer(container packedTableBuffer)
{   
    // A new table buffer is created on the server
TableBuffer serverTableBuffer = con2Buf(packedTableBuffer);

    // no RPC to the client...
serverTableBuffer.method1();

    serverTableBuffer.method2();

    serverTableBuffer.method3();       
   
    . . .

    // send back the new state of the table buffer to the client
return buf2Con(serverTableBuffer);
}

 

Microsoft provides programming examples for illustration only, without warranty either expressed or implied, including, but not limited to, the implied warranties of merchantability or fitness for a particular purpose. This mail message assumes that you are familiar with the programming language that is being demonstrated and the tools that are used to create and debug procedures.