Sunday 15 December 2013

issues during changing index uniqueness



Some times we need to create a new unique index or alter existing one, but table may already contain duplicate data for this index and our changes could not be applied until data in table fixed to support uniqueness. We could do it by deleting records in the table but due to huge number of companies in environment it could be time consuming. To save your time you could use following job:
static void Job3(Args _args)
{
    MyTable myTable;
    DataArea da;
    int cnt;
    ;
    ttsbegin;
    while select da
    {
        cnt = 1;
        changecompany(da.Id)
        {
            myTable = null;
            while select forupdate myTable
            {
                cnt++;
                myTable.FieldForUniqueness = int2str( cnt );
                myTable.update();
            }
        }
    }
    ttscommit;
}
Another way to solve this problem is to make following steps:
  1. Try to synchronize your table
  2. You get an error saying that there are duplicates
  3. Rright away you go to Administration > Periodic > SQL Administration form.
  4. Select your table in the list and run Table actions > Check/Synchronize command.
  5. In appeared form enable “Check Allow duplicated’” and run.
  6. You will get a list of conflicting records to kill.

Problem Solving Techniques in Axapta



Sometimes, when developing, AX doesn’t work as expected, or behaves weird.
Here are some of the things you can try if you run out of ideas, roughly in the order I do:

Try again
You probably already did, but make sure you can reproduce the problem. If it only occurred once, it’s not a problem.

Check your code again
Check your code carefully for errors, and maybe ask a colleague’s opinion.

Compile
Your project might contain compile errors, so compile it to be sure.

Close the debugger
Sometimes, when the debugger is active, AX will keep executing ‘old’ code. Close the debugger to make sure the latest code is executing.

Compile forward
When you have modified a class that is inherited by other classes, you might want to compile forward this class.

Synchronize data dictionary
You may have made changes to application objects that haven’t been synchronized with the database. Open the AOT, right click on the Data Dictionary node and choose Synchronize.

Restart AX client
Simple as that, close the AX client and start it again.

Reset usage data
Go to options screen (AX button > Extra > Options) and click the Usage Data button. Click reset to remove this data.

Check the application event log for clues
Open the event viewer on the AOS to see if the AOS service has logged something in it. Messages here can help you a great deal. You can also check the event log on the database server or your client pc.

Google it
If you receive an error, just copy and paste it in Google. Most likely you are not the only one having that problem.

Check your client version
Check your AX client version. You might for example be connecting to a SP1 application with an SP0 client. You can check this in the about screen: AX button > Help > About. The kernel version indicates the client version, below that is the application version.

Refresh AOD, Dictionary and Data
You can flush cashed information using three option in the Tools > Development tools menu: refresh AOD, refresh Dictionary and refresh Data. This can be useful when you just imported an xpo file, or when you are developing for the enterprise portal.

Delete AUC file
The application Unicode object cache file, if there is one, is located at C:\Documents and Settings\[USERNAME]\Local Settings\Application Data for xp, or C:\Users\USERNAME\AppData\Local for vista. Delete this file while the AX client is closed.

Check if other users are having the same problem
Knowing whether you are the only one that’s having that problem or if it’s a general problem is a big step towards solving the problem. For example, if you alone have the problem, restarting the AOS probably won’t solve it, but removing usage data might.

Check security settings
When only some users have a problem, big changes are that it has something to do with security settings. Security can be set up from Administration > Setup > Security, on the Permissions tab.

Check configuration key setup
Some features of AX won’t work if a configuration key is disabled, be aware of this.

Full compile
Open the AOT, right click the AOT node and select compile.

Restart AOS
Sometimes restarting the AOS solves your problem just fine. If you can, it’s worth the try as this doesn’t take long.

Remove .aoi file
When the AOS is stopped, you can delete the .aoi file from the application files. This file will be rebuilt when the AOS starts.

AX2012 Solution for time consuming Deploy SSRS Report Process

When Deploying the report from visual studio in some environments its taking lot of time to deploy, as it is verifying the privileges with the AD and ADServer is slow, some times I found its taking atleast 20mins to deploy a report.

So please use powershell with the following command to deploy the report with the parameters.

Publish-axreport -reportName <raportname> -SkipReportServerAdminCheck

Custom Lookup using lookupReference method in AX2012

In this article, giving an example for defining the lookup using lookupReference  method in simple way.

step 1 .

Override the lookupReference method on a required filed node in forms datasourse .


public Common lookupReference(FormReferenceControl _formReferenceControl)
{
  
    return MytableToGetLookup::getlookup(_formReferenceControl );
}

Step 2 .
Define method on table from where you have to get the values in the lookup

public static Common lookupReceiptLayout(FormReferenceControl  _ctl, SomeFilter  _someFilter)
{
    SysReferenceTableLookup sysTableLookup = SysReferenceTableLookup::newParameters(tablenum(RRPRReceiptLayout), _ctl, true);
    Query                   query = new Query();
    QueryBuildDataSource    queryBDS;
    MytableToGetLookup     _mytableToGetLookup
    ;
   
    // add the fields to show in the looup
    sysTableLookup.addLookupfield(fieldNum(MytableToGetLookup     , field1));
    sysTableLookup.addLookupfield(fieldNum(MytableToGetLookup     , field2));
   
    queryBDS = query.addDataSource(tablenum(MytableToGetLookup     )); //add datasourse
   
    queryBDS.addRange(fieldnum(MytableToGetLookup  , fieldToAddFilter)).value(_someFilter); // add filter
   
    sysTableLookup.parmQuery(query);
     _mytableToGetLookup = sysTableLookup.performFormLookup();

    return   _mytableToGetLookup ;
}

Dynamics AX will display the results of the query, based on the filter we've created. So the user will only be able to see what we want him to see, and so he'll only be able to select what we want. The problem is that if he types in an existing record in the control, even if does not get shown in our lookup, Dynamics AX will accept that.

To avoid that the user does in fact type in something we don't want, we'll have to override the validate method .


 

Custom lookup in dialog In Dynamics Axapta 2012

If you ever need to create a Dynamics AX dialog custom lookup, don't use the method naming approach, in which you name your method with a sufix like "_lookup". Your code will get very ugly, because the name of the fields in a dialog have very weak semantics. You'll most likely end up with methods like:

public void Fld1_1_lookup()

Instead use the new method introduced in Dynamics AX 2012, the DialogField.registerOverrideMethod method.


The method is very straightforward: you indicate what method you want to override, what is the method that overrides it, and in which form you want it to be overridden. Since it works with dialogs, you can use it on SysOperation UI Builders, on forms' dialogs and so on.

Because this method requires that the dialog is already constructed, you usually put it in "postRun" methods, like dialogPostRun or simply postRun, it depends on what you're doing. For SysOperationUIBuilders, you should call this method on the postBuild method.


For what I've seen and tested, the method that will receive the "event" we have overridden must always accept a first parameter of type FormControl, otherwise it just won't work.

Your method should look something like this:

private void lookup(FormControl _formControl)


Here's a full example of a lookup for a SysOperationUIBuilder, where we will override a lookup for a dialog field bound to the data contract:


  • Here we register the method that will be used to override the lookup method

     
     
     
     
     
     
     
     
     
     
     
     
    public void postRun()
    {
        DialogField           dlgFieldToBeOverridden;
        MyDataContract        dataContract;
          
        super();
      
        dataContract = this.getDataContractObject();
      
        dlgFieldToBeOverridden = this.bindInfo().getDialogField(dataContract, methodStr(MyDataContract, parmFieldToBeOverridden));
      
        dlgFieldToBeOverridden.registerOverrideMethod(methodStr(FormStringControl, lookup), methodStr(MyUIBuilderClass, myCustomLookup), this);
    }
  • And here's the method that will perform the actual lookup. For this particular example, we will assume we already have developed a new form called "MyLookupForm", and that we will be performing the lookup from a string control. You could use the SysTableLookup or the SysReferenceTableLookup approaches instead.

     
     
     
     
     
     
     
     
     
     
     
    private void myCustomLookup(FormControl _formControl)
    {
        Args                args            = new Args(formStr(MyLookupForm));
        FormStringControl   stringControl   = _formControl;
        FormRun             formRun;
      
        formRun = ClassFactory::formRunClassOnClient(args);
        formRun.init();
      
        stringControl.performFormLookup(formRun);
    }

Custom Lookup for Dimensions in AX 2012 – for User Defined Dimensions

In this blog , giving an example for defining the lookup for dimensions in simple way.
This example will cover only for user Defined dimensions.
For this
1)      Created a form and added two string controls.
2)      Named as
Control: Name: Dimensionlist, Auto declaration – Yes
Control: Name: DimValues

3)      Override the lookup method for Dimensionlist
public void lookup()
{
Query           query;
SysTableLookup  sysTableLookup;
super();
sysTableLookup = SysTableLookup::newParameters(tableNum(DimensionAttribute), this);
sysTableLookup.addLookupfield(fieldNum(DimensionAttribute, Name));
query = new Query();
query.addDataSource(tableNum(DimensionAttribute)).
addRange(fieldNum(DimensionAttribute, Type)).
value(queryValue(DimensionAttributeType::CustomList));
sysTableLookup.parmQuery(query);
sysTableLookup.performFormLookup();
}
4)      Override the lookup method for DimValues
public void lookup()
{
DimensionAttribute                  dimensionAttribute;
DimensionAttributeDirCategory       dimAttributeDirCategory;
Query                               query = new Query();
SysTableLookup                      sysTableLookup;
dimensionAttribute = DimensionAttribute::findByName(Dimensionlist.text());
super();
// Only user defined dimensions will have a financial tag category
if (dimensionAttribute.Type == DimensionAttributeType::CustomList)
{
select firstonly DirCategory from dimAttributeDirCategory where dimAttributeDirCategory.DimensionAttribute == dimensionAttribute.RecId;
sysTableLookup = SysTableLookup::newParameters(tableNum(DimensionFinancialTag), this);
// Add name field to be shown in the lookup form.
sysTableLookup.addLookupfield(fieldNum(DimensionFinancialTag, Value));
sysTableLookup.addLookupfield(fieldNum(DimensionFinancialTag, Description));
query = new Query();
query.addDataSource(tableNum(DimensionFinancialTag)).
addRange(fieldNum(DimensionFinancialTag, FinancialTagCategory)).
value(queryValue(dimAttributeDirCategory.DirCategory));
sysTableLookup.parmQuery(query);
// Perform the lookup.
sysTableLookup.performFormLookup();
}
}
Run:
Dim list
Dim Values
We can use the same concepts for Dimension controls on Ax 2012 SSRS reports dialog. To build the report dialog UI with dimension controls.

Friday 6 December 2013

How to add or delete a label file in Dynamics AX 2012

By now, you all must be aware that we are done with AOD files in Dynamics AX 2012. Model is the new deployment option for deploying AX objects on various installations. If you want to learn more about models, MFP has an excellent three part series on it which you can read here.

In this post we will look at how label files are contained within models in Dynamics AX 2012.

We now have a new node in AOT - Label Files

All labels in the system are grouped under this node.

Now suppose we have a label from another installation which we want to bring in to our system. Right click on the Label Files node and select Create from File. Browse and selct your .ald file. Once you select the file and hit OK, a new node is added under the Label Files node corresponding to the label file imported. You will get an info message saying "Imported label file:C:\Users\Administrator\Desktop\MyLabelen-us.ald"

In AX 2009, after placing a label file, we needed to restart the AOS so that the label index was build. This isn't required in Dynamics AX 2012. Just try using the label somewhere, and you will see that it is immediately referenced.

If you search in your application folder, you wont find the label file there. The application folder is located here C:\Program Files\Microsoft Dynamics AX\60\Server\MicrosoftDynamicsAX\bin\Application\Appl\Standard

In Dynamics AX 2012, the label file is imported in your current model.

Now let us restart the AOS and see what happens. After restarting the AOS, go back to your application folder and try to find the label file again. This time the label file will be found.

Point to remember, on every AOS restart, all label files will be copied to the application folder from the model store. So your label files are contained in your models but they are stored in your application folder as well.

Now let us try to delete the label file. Right click on your label file. Do you see a delete/remove option?

The answer is no. So how do we delete the label file then? The solution which I figured out was,
  1. To create a temporary model
  2. Move our label file to the temporary model
  3. Stop the AOS
  4. Delete the temporary model
  5. Start the AOS
Let us get about with these tasks
  1. Go to Tools -> Model management -> Create model
  2. Enter name as TemporaryModel. Press OK. You will recieve an info message saying "The model TemporaryModel was created successfully in layer var."
  3. Right click on your label file and select "Move to model"
  4. Select the TemporaryModel checkbox and press OK.
  5. Stop the AOS.
  6. Open a command prompt. We will be using the command line utility AXUTIL to delete the model.
  7. Issue the following command in the command prompt
  8. AXUTIL delete /model:TemporaryModel
  9. You will be prompted if you want to delete the model or not. Press Y
  10. Start the AOS
  11. Delete the label file from your application folder as well.
When you open AX now, you will get a dialog saying that "Your model store has been modified." This is normal because each time you perform an operation on a model, you will get this dialog. Depending on your operation, you should select one of the option. Since we just deleted a model which just had a label file, select Skip.
Open AOT and notice that the label file is deleted now.
Check if the references of the label work. I bet they wont be.

In this post we learnt how label files are managed in Dynamics AX 2012, how to import a label file and how to delete them.

X++ Code to remove the duplicate objects in AOT

Use the following code to delete the identical copy

static void FindAndDeleteIdenticalObjects(Args _args)
{
SysTreeNode comparable1, comparable2;
TreeNode curLevelTreeNode, upperLevelTreeNode;
UtilIdElements utilElements, joinUtilElements;
;
while select UtilElements
where UtilElements.utilLevel == UtilEntryLevel::var &&
(
UtilElements.recordType == UtilElementType::Form ||
Utilelements.recordType == UtilElementType::Report ||
Utilelements.recordType == UtilElementType::Table ||
Utilelements.recordType == UtilElementType::Class ||
Utilelements.recordType == UtilElementType::Enum ||
Utilelements.recordType == UtilElementType::ExtendedType
)
{
//Should use join if for a normal table, but not applicable for UtilElements
//Performance hit if use exists join
select firstonly recid from joinUtilElements
where joinUtilElements.utilLevel != UtilElements.utilLevel &&
joinUtilElements.name == UtilElements.name &&
joinUtilElements.recordType == UtilElements.recordType;
if (joinUtilElements.RecId)
{

curLevelTreeNode = SysTreeNode::findNodeInLayer(UtilElements.recordType, UtilElements.name, UtilElements.parentId, UtilElements.utilLevel);
upperLevelTreeNode = SysTreeNode::getLayeredNode(curLevelTreenode, 1);
comparable1 = SysTreeNode::newTreeNode(curLevelTreeNode);
comparable2 = SysTreeNode::newTreeNode(upperLevelTreeNode);
if (SysCompare::silentCompare(comparable1, comparable2))
{
info(strFmt("Element name: %1, Element type: %2", UtilElements.name, enum2str(UtilElements.recordType)));
//Remove the node
curLevelTreeNode.AOTdelete();
}
}
}
}

License in Dynamics Ax

AX stores the License data in the two tables.

1.SysLicenseCodeSort
2.SysConfig

Import these tables from Running instance at your instance , this will serve your purpose.

how to update the system fields of the table

Usually in the transaction table while data copying from older version to newer version, we require to copy the system fields as well like (ModifiedDateTime, ModifiedBy, CreatedDateTime, CreatedBy). These fields are system generated fields and user cant update the values in these fields In a normal manner. We have to do a bit trick to fool the compiler
Wrong way : Compiler will not allow this and give you the error “The field must be a data element that allows assignment.”
LedgerTrans ledgerTrans;  
 ;  
 ttsbegin;  
 ledgerTrans.modifiedDateTime = DateTimeUtil::utcNow();  
 ledgerTrans.update();  
 ttscommit;  
Correct way: you can make the compiler silent with below modifications
LedgerTrans ledgerTrans;  
 ;  
 ttsbegin;  
 ledgerTrans.overwriteSystemfields(true);  
 ledgerTrans.(fieldNum(LedgerTrans,modifiedDateTime)) = DateTimeUtil::utcNow();  
 ledgerTrans.update();  
 ttscommit;