A blog offering various X++ code snippets and tips for Microsoft Dynamics AX

Tuesday, February 03, 2009

Table buffers: Deep Copy vs Shallow Copy

Some people ask:

"What is the difference between using the equal assignment sign '=' between buffers and using the using the .data() method?".

It's a question of deep copy and shallow copy.

In the following X++ code snippets follow the RecId number of the buffer called currentSalesTable. Please ssume the RecId of the currently selected record in the datasource is 100 and that the current selected record is not the first (top) record in the form.


void exampleMethod()
{
SalesTable copySalesTable;
;
// copySalesTableRecId = 0
copySalesTable = SalesTable;
// copySalesTableRecId = 100

// do some processing

SalesTable_ds.executeQuery();
// SalesTable RecId now changed to 90

// copySalesTable RecId = 90 i.e. shallow copy
info(num2str(copySalesTable.RecId, -1, -1, -1, -1));
}



void exampleMethod()
{
  SalesTable copySalesTable;
  ;
  // copySalesTableRecId = 0
  copySalesTable.data(SalesTable);
  // copySalesTableRecId = 100

  // do some processing

  SalesTable_ds.executeQuery();
  // SalesTable RecId now changed to 90

  // copySalesTable RecId = 100 i.e. deep copy
  info(num2str(copySalesTable.RecId, -1, -1, -1, -1));
}


Therefore as you saw from the above code snippets the .data() method is actually a deep copy while the assignment '=' operator is just a reference because when the datasource 'SalesTable' buffer changed, in the first code snippet, the 'copySalesTable' buffer also changed while in the second case the copy kept its first RecId value.

However, there is an exception to this rule. This rule does not work if you update the original buffer (SalesTable in the above code - the buffer I'm copying from, in the code below i.e. originalSalesTable) with a shallow copy.

Consider the following code snippet and its comments:

static void Job6(Args _args)
{
  SalesTable originalSalesTable,
      copySalesTable,
      copySalesTable2;
  ;
  select firstOnly originalSalesTable;

  copySalesTable = originalSalesTable;
  copySalesTable2.data(originalSalesTable);

  info (num2str(copySalesTable.RecId, -1, -1, -1, -1));
  info (num2str(copySalesTable2.RecId, -1, -1, -1, -1));

  // using .data() method to mimic change in datasource / deep copy
  originalSalesTable.data(SalesTable::find('01323_036'));

  // the rule I'm describing in this post does not work if I used the following:
  // uncomment the line below and comment the line above to test
  // originalSalesTable = SalesTable::find('01323_036');

  info (num2str(copySalesTable.RecId, -1, -1, -1, -1));
  info (num2str(copySalesTable2.RecId, -1, -1, -1, -1));
}


Copy and paste this last code snippet if you want to test this exception to the rule I'm trying to put forward :-)

If you any questions or comments e-mail me on: mirko@mirkobonello.com

Getting the number of decimal places for an EDT

Sometimes you might need to get the amount of decimal places set on the EDT. This can either be set to 'AUTO', where the decimal places set in the server's regional settings are taken or manually inputted by the developer in the property inspector.

The following is a code snippet of how this can be done, catering for both scenarios mentioned above:


#DEFINE.AUTO('Auto')

#AOT
#PROPERTIES
#WinAPI // Used for regional settings

TreeNode treeNode;
Int decimalPlaces;
;
treeNode = infolog.findNode(#ExtendedDataTypesPath + '\\' + identifierstr(YourEDT));

if (findproperty(treeNode.AOTgetProperties(),#PropertyNoOfDecimals) == #AUTO)
{
  // get the number of decimals from the regional settings
  decimalPlaces = str2int((WinAPI::getLocaleInfo(#LOCALE_USER_DEFAULT,   #LOCALE_ICURRDIGITS)));
}
else
{
  // get the number of decimals set by the developer in the property inspector
  decimalPlaces = str2int(findproperty(treeNode.AOTgetProperties(),#PropertyNoOfDecimals));
}

info (int2str(decimalPlaces));


If you any questions or comments e-mail me on: mirko@mirkobonello.com