Wednesday, October 23, 2013

Debugging update conflicts with X++

Let's say, you need to figure out why an update conflict happens, but there is no way to find that with cross-references (e.g., if doUpdate() method is called somewhere).

Normally, you could use SQL Server Management Studio, while debugging the main logic. Simply set transaction isolation level to "read uncommitted" and periodically check RecVersion field value in the "problematic" record .

However, if there is no access to the SQL Server management Studio, try the following approach:

1. Open another AX client and development workspace.
2. Create a class and add main-method to it.
3. Paste the following code to the main method:
 
public static server void main(Args _args)
 {
     Connection      connection;
     Statement       statement;
     str             query;
     Resultset       resultSet;
 
     connection = new Connection();
     statement = connection.createStatement();
 
     query  = "SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;";
 
     query += @"SELECT RecVersion FROM PurchLine                "; 
     query += @"    WHERE PurchLine.InventTransId = N'11199055' ";
     query += @"      AND PurchLine.dataAreaId    = N'CEU'      ";
 
     new SqlStatementExecutePermission(query).assert();
 
     resultSet = statement.executeQuery(query);
 
     while (resultSet.next())
     {
         info(resultSet.getString(1));
     }
 
     CodeAccessPermission::revertAssert();
 }

4. Adjust the query string as needed.
5. Go through the main logic in the debugger and periodically run this class in the second workspace, so you will know if the RecVersion value is still the same.

3 comments:

  1. Hi Sasha,

    How detecting the recversion could help you identify the location of the update conflict ?

    ReplyDelete
    Replies
    1. Hi Kamalakannan

      As you know, update conflict happens when RecVersion value of the local table buffer, which is being updated, and the corresponding record in the DB is different.

      This script helped me avoid unnecessary "step in"-s in the debugger, because I could immediately see, if some particular line of code resulted in the "hidden" update. Then I could put a breakpoint onto this line, step in and and debug again, until the actual update_recordset, doUpdate() or update() call was found.

      Delete
  2. Alternative approach is to enable SQL tracing of all statements in user options dialog of Dynamics AX and set it to file. Let your process execute until it throws the update conflict exception and then search for the last UPDATE statement on this table in the trace file. There you will also see the X++ call stack which issued this update statement.

    ReplyDelete