Free: AN INTRODUCTION TO DYNAMICS AX 2012 (Dynamics AX Companion Guides)

2015-07-24_1435Its not really my habit in my blog to re-post or re-blog other users content, but rather to write up my own findings as I explore Dynamics AX. However this post is a bit of a worthy exception.

If you have been in AX for an period of time you have most likely heard of Murray Fife and his very practical Companion guides to Dynamics AX. Right now you can download his “AN INTRODUCTION TO DYNAMICS AX 2012” for free over here. It is highly useful material for anyone new to AX or even old hats looking for some new easy to use tips and tricks. I’ve been compiling some introductory basic training material for our company and this book will go along way in assisting me with this!

Thank you Murray Fife for this awesome content.

See his original post over here too.

https://www.linkedin.com/pulse/free-prize-download-introduction-dynamics-ax-2012-murray-fife?trk=prof-post

Update: Unfortunately this was only a limited time offer, but I would still encourage you to get hold of this book either from Murray Fife’s website http://www.dynamicsaxcompanions.com/ or from amazon  Here

Beware the “Catch”

Recently while debugging some legacy code I came across the following interesting observation regarding transaction scopes (ttsbegin, ttscommit) and the exception handling surrounding it. While walking the legacy code was observing very strange and unexpected behaviour and after some online investigation i found the following statement from Microsoft:

“When an exception is thrown inside a ttsBeginttsCommit transaction block, no catch statement inside that transaction block can process the exception. Instead, the innermost catch statements that are outside the transaction block are the first catch statements to be tested.”
(
https://msdn.microsoft.com/en-us/library/aa893385.aspx)

In its simplest form this means that for the following code:

 try
    {
        ttsBegin;
        try
        {
            throw error("Thrown Error");
        }
        catch (Exception::Error)
        {
            error("Inside Error");
        }
        ttsCommit;
    }
    catch (Exception::Error)
    {
        error("Outside Error");
    }

Prints the following results:
2015-07-23_0801

Now when it comes to a simple block of code like above one may say “Well that is simply silly coding”, however it becomes harder to anticipate results when that inner try…catch is within a method somewhere deeper inside the call stack (perhaps in standard code somewhere) e.g.

    void innerFunction()
    {
        try
        {
            ttsbegin;
            throw error("Thrown Error");
            ttscommit;
        }
        catch (Exception::Error)
        {
            error("Inside Error");
        }
    }
    
    try
    {
        ttsBegin;
            innerFunction();
        ttsCommit;
    }
    catch (Exception::Error)
    {
        error("Outside Error");
    }

Further more if your inner exception does cleanups or logging of information this will not happen by carelessly adding ttsBegins and ttsCommits around the calling code E.G. “writeErrorLog” will never be called in the following function regardless of what the writer of “innerFunction” does if the writer of the caller adds TTSBEGIN AND COMMIT

static void testTransactions(Args _args)
{
    void innerFunction()
    {
        while forUpdate select myTable
        {
            try
            {
            
                ttsBegin;
                if (someCondition)
                {
                    throw error("Throw Error");
                }
                else
                {
                    myTable.myField = "update";
                    myTable.update();
                }
                ttsCommit;
            }
            catch (Exception::Error)
            {
                writeErrorLog(strFmt("Failed on record %1", myTable.RecId));
                error("Inside Error");
            }
        }
    }
    
    try
    {
        ttsBegin;
            innerFunction();
        ttsCommit;
    }
    catch (Exception::Error)
    {
        error("Outside Error");
    }
}

I thought I would just paste these observations for anyone who like me has experienced this type of “strange behavior” in the past and didn’t know the exact reason and also as a warning to beware of the “Catch”.

Feel free to share your comments, observations and thoughts.

 

 

 

 

Setup DB Logging in X++ (Updating events)

Setting up AX Database logging via the user interface wizard can at times be a bit of a cumbersome and slow task, especially for tables that are not very common. The job below will simply set database logging for all fields on a specific table. Simply replace “InventSalesSetup” with the table name of your own choosing. As always, test this in a non-production environment to confirm that it performs suits your own needs.

static void setDBLogOnTable(Args _args)
{
    TableId tableId = tableNum(InventItemSalesSetup);
    DatabaseLog log;
    SysDictTable dictT = new SysDictTable(tableId);
    SysDictField dictF;
    Set fields;
    SetEnumerator   se;


    log.logType = DatabaseLogType::Update;
    log.logTable = tableId;
    fields = dictT.fields(false,false,true);
    se = fields.getEnumerator();
    while (se.moveNext())
    {
        dictF = se.current();

        log.logField = dictF.id();
        log.insert();
        info(strFmt("Adding field %1", dictF.name()));
    }
    SysFlushDatabaselogSetup::main();
}