Tuesday, October 20, 2015

Copy sub folders and files by using X++

As far I know, In AX 2012, there is no direct functionality available to copy the files and sub directories. First we can create the sub directories recursively and copy the all source files to destination path.

I have created simple job for your reference.

static void Hari_CopyFolderAndFiles(Args _args)
{   
    str             source = @"F:\AX\Hari\Test";
    str             dest = @"F:\AX\Hari\Destination";
    str             tempFolderPath;
    System.String[] directories = System.IO.Directory::GetDirectories(source, "*.*", System.IO.SearchOption::AllDirectories);
    int             folderCount = directories.get_Length();
    int             currentFolderCount;
    void copyAllFiles(str sourceFolder, str destFolder)
    {
        str                 tempDestFileName;
        System.String[]     filePaths = System.IO.Directory::GetFiles(sourceFolder, "*.*", System.IO.SearchOption::AllDirectories); //get listing of all files within the folder
        System.IO.FileInfo  sourceFile;
        int                 fileCount = filepaths.get_Length();
        int                 currentFileCount;
    
        for(currentFileCount = 0; currentFileCount < fileCount ; ++currentFileCount)
        {
            sourceFile = new System.IO.FileInfo(filepaths.GetValue(currentFileCount));
            tempDestFileName = strReplace(filepaths.GetValue(currentFileCount), sourceFolder, destFolder);
            //Copy file
            sourceFile.CopyTo(tempDestFileName, true);           
        }
    }
  
    //Create sub directories
    for(currentFolderCount = 0; currentFolderCount < folderCount ; ++currentFolderCount)
    {
        tempFolderPath = strReplace(directories.GetValue(currentFolderCount), source, dest);
        if(!System.IO.Directory::Exists(tempFolderPath))
        {
            System.IO.Directory::CreateDirectory(tempFolderPath);
        }
    }
   
    //Copy all files include sub directory files
    copyAllFiles(source, dest);
    info('Success');

Saturday, September 26, 2015

Models, Layers and Model store

AX 2012 database structure:

AX 2012 is having two databases. One for data another one for model store. You can find which data db is mapped with AX instance by using AX 2012 server configuration application. The model store name mostly named with data db name + “_model”. For example: your data db name is MicrosoftDynamicsAX2012 then your model store db name should be like MicrosoftDynamicsAX2012_model.

AX 2012 data database

Business data are stored on the data database the named like “MicrosoftDynamicsAX2012” based on your installation. For example, the data is customers, vendors, sales order, purchase order and so on

Models

Models are working based on single layer. We can create multiple models on the single layer. We are doing customization on the models. So, our customizations are stored on the model store. We shouldn’t use single element in multiple models and that models are in a single layer. It will create id conflict issue.

Layers

AX 2012 is having default application layers SYS, GLS, FPK, SLN, ISV, VAR, CUS and USR. layers are used to manage elements (for example: table, class, forms). The top layer is USR and bottom layer is SYS. If you do the customization on the VAR layer, that customization will affect in the VAR, CUS and USR layers.
For example, you add one table named table1 with two fields name and class in the VAR layer. You are removing the class field from the table table1 in the USR layer.
VAR, CUS layer having table table1 and two table fields named name and class. But, USR layer is having table1 table but only one table fields named name.
Each layer has a corresponding patch layer that can be used to incorporate updates to your application or to store conflicts when you import models into a layer. For more information about patch layers, see Patch Layers https://msdn.microsoft.com/en-us/library/aa891248.aspx.

Based on your license and configuration you can do your customization on the particular layer. To do your customization on the particular layer, you can find your license code on the customer source website or you can get from your Microsoft Dynamics partner. You can change the layer by using AX 2012 configuration application.

Model store

All models (For example: cus Model, var Model, usr Model and so on) are stored on the model store database.

As per the AX database structure, you came to know that data db tables and model store db data having relations. If you create new table on the SQL directly instead of on AX development environment, you will face some synchronization issue. You may not access that table in the AX workspace. Your newly created table won’t be created when you do model move or model store move. It is not a best practice.

Monday, September 7, 2015

Which layer is best option for customization in AX 2012?

It is good for choosing the right layer.

For best customer development we can go ahead with VAR. For this we must have VAR code from Microsoft.

Layer
Description
USR
The user layer is for user modifications, such as reports.
CUS
The customer layer is for modifications that are specific to a company.
VAR
Value Added Resellers (VAR) can make modifications or new developments to the VAR layer as specified by the customers or as a strategy of creating an industry specific solution.
ISV
When an Independent Software Vendor (ISV) creates their own solution, their modifications are saved in the ISV layer.
SLN
The solution layer is used by distributors to implement vertical partner solutions.
FPK
The FPK layer is an application object patch layer reserved by Microsoft for future patching or other updates. For more information, see Patch Layers.
GLS
When the application is modified to match country or region specific legal demands, these modifications are saved in the GLS layer.
NoteNote
The GLS layer is consolidated into the SYS layer in Microsoft Dynamics AX 2012 R3.
SYS
The standard application is implemented at the lowest level, the SYS layer. The application objects in the standard application can never be deleted.



Sunday, August 9, 2015

Index

Index:

Indexes are used to improve the database search and retrieve functionality. We can add one or more fields in the indexes. Indexes are managed automatically by the DBMS when we do the operation insert, update and delete. We don’t want to create the index if the table mostly used for insert the values. Index is right choice for tables that mostly using for search functionality. We can’t create index for the datatypes memo and container fields. In AX 2012, all tables having default index for the fields recid and dataareaid.

Two types of indexes are in AX 2012.
  1. Unique
  2. Non unique

Unique:

We can unique index by setting the property AllowDuplicates to Yes. Once we created the unique index for the fields, we can’t insert duplicate value, the system will handle automatically and throw error message when we insert the duplicate values. We can select the unique index as table primary index.

Non unique:

It allows duplicate values.

We can enable and disable the index by setting the index property Enabled. DBMS will handle index once you re-enable the index. We can also delete the index.

We can use the index in the select statement to improve the fetching speed. For example

while select AccountNum, Name from custTable index AccountIdx { ……. }

Monday, May 18, 2015

Ternary Operator (?)

Introduction:

Ternary operator is a conditional statement. It is related to the If condition, but it assigns value to the variable. Based on the scenario, we can use ternary operator instead of If condition.

Syntax:

expression1 ? expression2 : expression3

Expression1 must be a Boolean expression. Expression1 may be a condition for example:

salaryDeduction = calculatedDeduction > 500 ? calculatedDeduction - 500 : 0;

expression2 and expression3 must be a same data type otherwise, it will be consider as error. You may get warning/error message like “Operand types are not compatible with the operator”.

As per the above code if the calculatedDeduction is more than 500 then expression2 result value will be assigned to the variable salaryDeduction else 0 will be assigned to the variable salaryDeduction. It is also possible to use ternary statement nested inside another ternary statement. Last time, I tried this ternary operator in the update_recordset, but not supported.

Replace If condition:

Based on the scenario, we can use ternary operator instead of if condition.

Saturday, May 16, 2015

Array

Introduction:

Array is a collection of same data type variables. We can access the each element in the array by using index. The index is start with 1. Sometimes, we have to deal with same data type value collections like name of the persons. For this scenario, we can use array data type.
Array data type is one of the composite data type in AX 2012. We can’t use Array data type for store the class objects. But, we can use Array collection class instead of Array data type.
AX 2012 supports only single dimension array not multi dimension array.

Array example:

static void Hari_TestJob(Args _args)
{
    str empName[10];       // Fixed-length array with 10 integers
    empName[1] = 'Hari'; //Assign value to the 1st element in the array
    print empName[1];     //Accessing the 1st element in the array
    pause;
}

Types of array

Three types of arrays are in AX.
  1. Fixed length
  2. Dynamic length
  3. Partly on disk


Fixed length:

Declare the length of the array in the variable declaration section. For example:
    str empName[10];
As per the above declaration code, we can hold only 10 values in this array.

Dynamic length:

Declare the array without mention the length. For example:
    str empName[];
Array length is the unlimited here. Array length is calculated based on the maximum element index used.

Partly on disk:

Partly on disk is some elements occupied in memory and others are occupied on disk. We can use fixed length array and dynamic length array in the partly on disk type. We can use this type for performance optimization when deal with lot of data. For example:
    //Fixed length array in the partly on disk array type,
    //here 20 items in the memory and 100 items in the disk.
    str empName[100, 20];
    //Dynamic length array in the partly on disk array type,
    //here 20 items in the memory and other items in the disk.
    str empName[, 20];

Reset the array values:

We can reset all array element value by assign any value to the 0 element of the array. For example:
static void Hari_TestJob(Args _args)
{
    str empName[10];
    empName[1] = 'Hari';
    empName[0] = '';         // Reset the array values
    print empName[1];
    pause;
}

Get the array length:

We can get the length of the array by using the dimOf function.


Tuesday, April 7, 2015

Useful functions for container

conLen:

conLen function is used to get the container length.

conPeek:

conPeek is used to get the container content by index. Note: index starts by 1.

conIns:

conIns function is used to insert one or more elements into a container. For example:
static void Hari_Test_ConIns(Args _args)
{
    container   c;
    int         i;
    c = [3, 'third'];
    c = conIns(c, 1, 1, 'first', 2, 'second');
   
    for(i = 1; i <= conLen(c); i++)
    {
        info(strFmt('%1', conPeek(c, i)));
    }
}

Result:
1
first
2
second
3
third

Note: += is faster than conIns function. We can use conIns when you want to insert the element in the particular index.

conDel:

conDel function is used to delete the one or more elements from the container. For example:
static void Hari_ConDel(Args _args)
{
    container   c;
    int         i;
    c = [3, 'third'];
    c = conIns(c, 1, 1, 'first', 2, 'second');
    c = conDel(c, 5, 2);
    for(i = 1; i <= conLen(c); i++)
    {
        info(strFmt('%1', conPeek(c, i)));
    }
}

Result:
1
first
2
second

conFind:

conFind function is used to find the sequence elements in the container. For example:
static void Hari_ConFind(Args _args)
{
    container c = ["item1", "item2", "item3"];
    int i, j, k, l;
    ;

    i = conFind(c, "item2");
    j = conFind(c, "item1", "item2");
    k = conFind(c, "item1", "item3");
    l = conFind(c, "item4");
   
    print "Position of 'item2' in container is " + int2Str(i);
    print "Position of 'item1 item2' in container is " + int2Str(j);
    print "Position of 'item1 item3' in container is " + int2Str(k);
    print "Position of 'item4' in container is " + int2Str(l);
    pause;
}

Result:
Position of 'item2' in container is 2
Position of 'item1 item2' in container is 1
Position of 'item1 item3' in container is 0
Position of 'item4' in container is 0

conNull:

conNull function is used to empty or dispose the contents of the container.

conPoke:

conPoke function is used to replace the contents of the container from the particular index. For example:
static void Hari_TestJob(Args _args)
{
    container c1 = ["item1", "item2", "item3"];
    container c2;
    int i;

    void conPrint(container c)
    {
        for (i = 1 ; i <= conLen(c) ; i++)
        {
            print conPeek(c, i);
        }
    }
    ;
    conPrint(c1);
    c2 = conPoke(c1, 2, "PokedItem", "Test");
    print "";
    conPrint(c2);
    pause;
}

Result:
item1
item2
item3

item1
PokedItem

Test

Container Data Type in AX 2012

Introduction

Container is a one of the data type in ax. We can hold more primitive data type values in a single container. Container index starts by 1 not 0. For example:

container   c = ['Test', 27];
info(strFmt('%1 - %2', conPeek(c, 1), conPeek(c, 2)));

Result: Test – 27

Table Field Type:

Container is one of the table field data type. So, we can store the container directly in to the database table field. In SQL, container table field data type is treated as varbinary datatype field.

Store container in another container:

We can also store one container in another container. For example:

int         i;
container   c = ['Test', 27], d = ['Second'];   
c += d;
   
for(i = 1; i <= conLen(c); i++)
{
    info(strFmt('%1', conPeek(c, i)));
}

Result:
Test
27
Second

Value based:

It is a value based structure. We can’t store any class objects in this container. It is not a reference based data type. If you assign one container in another container, the container will be copied not linked by reference. For example:

int         i;
container   c = ['First'], d;   
c += d;
d += ['Second'];
for(i = 1; i <= conLen(c); i++)
{
    info(strFmt('%1', conPeek(c, i)));
}

Result:
First

When we use container

As per the above code, we add d container in c and adding “Second” string value in the d container after adding. But “Second” value is not added in the c container. So, if you pass container as argument to the method, it creates new container. So, performance will be slow.
If you want to handle different data types, container is the good choice. But, if you add repeated value like list in the container, it is not a good choice, because it will affect performance.

Containers are immutable

Immutable means once the variable is declaration, we can’t change the size. Here container is an immutable object. When we add, delete and update the container, new container will create.

The following statements all create a new container.

myContainer = [1]; // new container created for myContainer
myContainer += [2]; // new new container created for myContainer
myContainer4 = myContainer5; // new container created for myContainer4

Insert performance:


+= is faster than conIns function. We can use conIns when you want to insert the element in the particular index.

Sunday, April 5, 2015

Primitive data types in AX 2012

1. Anytype Data Type:

Anytype is a placeholder for any data types (integer, real, string, container, class, etc.).
Please refer this link for more information.

2. Booleans

We can use Boolean for true or false values.

3. Dates

Dates data type is used to handle date value (date, month, year).

Assign value:
date d1 = 31\3\2015;

We can add days and subtract date easily. For example:
date d1 = 31\3\2015;
d1 = d1 + 3; //Add two day, result: Apr 3, 2015
d1 = d1 - 1; //Subtract one day, Result Apr 2, 2015

Date range is Jan 1, 1900 to Dec 31, 2154

4. Enums

Enum is an abbreviation of enumerated text. It contains list of literals. Enum literals represented as integer values. First Enum literal value is 0, next literal value is 1 and so on. We can use maximum 251 literals in single Enum.

We can create Enum in the AOT -> Base Enums.  We can declare this Enum in X++ like other data types (ex: Integer)

Declaration:
NoYes    isCompleted;

Assign value:
isCompleted = NoYes::Yes;

If you assign this Enum data type EDT in the combo box, the Enum literals are coming as combo box options.

Enums as Radio button
If you drag the form data source enum field in the design, the combo box control will be added (combo box is default control for enums). If you want radio button (radiobutton) control instead of combo box, add the radio button control by right click on design node and go to New Control -> RadioButton. Set the data source and data field property of the radio button.

If you want to set Enums in the un bound radio button control, select the Enum Type or use ExtendedDataType properties.

5. GUIDS

GUID is a Globally Unique Identifier. It is a unique no across all computers and networks. The unique identifier is generated by Microsoft algorithm. We can use this data type if we need globally unique no.

Hint: To check the GUID empty value, we can use the nullValueBaseType Global class method.
Example:
if(this.PurchReqLineRefId == nullValueBaseType(Types::Guid))

6. Integers

It is a number without decimal point.
Two integer types are there:
int (32 bit)
int64 (64 bit)
int range is - 2,147,483,648 to 2,147,483,647
int64 range is - 9,223,372,036,854,775,808 to 9,223,372,036,854,775,807

Declaration:
int a = 27;

7. Reals

Real data type is used to hold decimal numbers.

Declaration:
real   r1 = 10.03;

8. Strings

It is used for strings (number of characters). Range is unlimited.
We can set the length in the StringSize property of the EDT or table field. In X++, we can set maximum length in the declaration section. For example:
str 60 testStr;
As per the above declaration code, we can assign only 60 characters.

9. TimeOfDay

TimeOfDay datatype variable is used to hold time of the day. It represents integer value. Its range is 0 to 86400 (86400 means 23:59:59).

TimeOfDay   t1 = 28800;
info(strFmt('%1', time2str(t1, TimeSeparator::Colon, TimeFormat::AMPM)));

Result: 08:00:00 am

time2str function is used to display the time in the specify format.

10. UtcDateTime

UtcDateTime variable is used to hold date and time value.

Assign value:
utcdatetime myUtc2 = 1988-07-20T13:34:45;

Friday, April 3, 2015

Anytype Data Type

What is Anytype Data Type

Anytype is a placeholder for any data types (integer, real, string, container, class, etc.). The data type will be initialized to the anytype variable when you assign a value. For example:

anytype test; //Declare anytype variable
test = 10; //assign a integer value

Variable initialize

After assigned the integer value we can treat anytype variable as integer variable.
Once the data type initialized to the anytype variable, we can’t assign other data type values. For example:

anytype test; //Declare anytype variable 
test = 10; //assign a integer value 
test = 'strValue'; 
info(strFmt('%1', test)); 

The info window will show the message “0”

Avoid "Wrong argument type for function" Error

One more thing, you will get a runtime error message when you use the anytype variable before you assign the value. But, we won’t get any compilation error. For example:

anytype test; //Declare anytype variable 
info(strFmt('%1', test));

Error message:
Error executing code: Wrong argument type for function.

So, before use the anytype variable, we can check the anytype variable is initialized or not. For Example:

anytype test; //Declare anytype variable 
if(!(typeOf(test) == Types::AnyType)) 

    info(strFmt('%1', test)); 
}

If we want to know the which datatype was set in the anytype variable, we can use the typeOf() method.

Using Anytype in Map class

We can use Anytype in the map class. For example:

Map TestMap = new Map(Types::Int64, Types::String); 
TestMap.insert(1, 'Test'); 
TestMap.insert(2, 1); 
TestMap.insert(3, 3.5); 
info(strFmt('%1', TestMap.lookup(3)));

Thursday, March 26, 2015

Variable declaration

Variable declaration

Variables must be declared first in the method. We can’t declare the variable inside the X++ statements. In other languages like .net, VB we can declare wherever you want. In AX 2009 we should use semicolon (;) to separate the declaration part and X++ statements like the below code.

AX 2009 variable declaration

int a;
;
a = 5;

But, in ax 2012 semicolon is not necessary (optional). We can assign values in the declaration part.
int a =5;

Variable name

In X++, variable names are not case sensitive. As per the naming convention standard, the first character of the variable name should be small letter. For example:
PurchLine purchLine

Data types

Primitive and composite data types are supported in X++. We can use EDT, table name, class name as data types. For example:
Name                    firstName, lastName;
PurchLIne            purchLine;
Access                  accessObject = new Access();

Multiple variable declaration

X++ allows you to add multiple variable declaration in the same declaration statement. For example:
int i,j;

real a = 5, b=3;

Sunday, March 15, 2015

Labels

What is label?

Labels in AX, is used to assign text to the objects ex. table fields. We can avoid to create duplicate text in label before create a new label by find the label in the label editor.
We should use labels for user interface text in forms and reports.

Label editor:

Label editor is an editor used to create, find, update and delete labels.
Open label editor:
In development workspace, Tools - > Label -> Label Editor


Create a label:

Open the label editor, click the new button and enter the text and description. Once you saved this label, the label id will create automatically the label id format will like @TES123. We can assign this label id to table field.


Assign label to the table fields:

Select the table field and go the properties window and select the label property, click the … button and enter the text, click the find button, the labels will come if the label already exist otherwise we need to create a new label.
If you know the label id then, we can directly enter the label id in the label property of the table field.




Use labels in the X++ code:

We can also use the labels in the x++ code.
For example: info('@SYS80122');

Use labels in the SSRS report:

We can use the AX labels in the AX SSRS report design. So, once we change label text in the AX label editor, it will automatically reflect in the SSRS report. Mention the label in the object expressions. For example: Lables!@SYS80122

Labels file:

The labels are stored in the label file. The label file is based on the language.
To create label files, Click Tools -> Wizards -> Label File Wizard
We can find the labels in the AOT -> Label files.

We can export and import this label files (.ald) to move the objects from one environment to another environment like development to production.