Exception Handling
It
is a best practice to use the X++ exception handling framework instead
of programmatically halting a transaction by using the ttsabort
statement. An exception (other than the update conflict exception)
thrown inside a transaction block halts execution of the block, and all
the inserts and updates performed since the first ttsbegin
statement are rolled back. Throwing an exception has the additional
advantage of providing a way to recover object state and maintain
database transaction consistency. Inside the catch block, you can use the retry statement to run the try block again. The following example demonstrates throwing an exception inside a database transaction block.
static void myJob(Args _args) { MyTable myTable; boolean state = true; ; try { ttsbegin; state = false; update_recordset myTable setting myField = "value" where myTable.id == "001"; if(state==false) { throw error("Error text"); } ttscommit; } catch(Exception::Error) { state = true; retry; } catch { print "Unhandled Exception"; pause; } }
|
The throw
statement throws an exception that causes the database transaction to
halt and roll back. Code execution can’t continue inside the scope of
the transaction, so the runtime ignores try and catch
statements when inside a transaction. This means that an exception
thrown inside a transaction can be caught only outside the transaction,
as shown here.
static void myJob(Args _args) { try { ttsbegin; try { ... throw error("Error text"); } catch //Will never catch anything { } ttscommit; } catch { print "Got it"; pause; } }
|
Although a throw statement takes the exception enumeration as a parameter, using the error method to throw errors is the best choice. The try statement’s catch list can contain more than one catch block. The first catch block in the preceding example catches error exceptions. The retry statement performs a jump to the first statement in the outer try block. The second catch block catches all exceptions not caught by catch blocks earlier in the try statement’s catch list. Table 8 describes the Dynamics AX system Exception data type enumerations that can be used in try-catch statements.
Table 8. Exception Data Type Enumerations
Element | Description |
---|
Deadlock | Thrown when a database transaction has deadlocked. |
Error | Thrown when an unrecoverable application error occurs. A catch block should assume that all database transactions in a transaction block have been halted and rolled back. |
Internal | Thrown when an unrecoverable internal error occurs. |
Break | Thrown when a user presses the Break key or Ctrl+C. |
DDEerror | Thrown when an error occurs in the use of a Dynamic Data Exchange (DDE) system class. |
Sequence | Thrown by the Dynamics AX kernel if a database error or database operation error occurs. |
Numeric | Thrown when an unrecoverable error occurs in the str2int, str2int64, or str2num system function. |
CLRError | Thrown when an unrecoverable error occurs in a CLR process. |
CodeAccessSecurity | Thrown when an unrecoverable error occurs in the demand method of a CodeAccessPermission object. |
UpdateConflict | Thrown when an update conflict error occurs in a transaction block using optimistic concurrency control. The catch block should use a retry statement to attempt to commit the halted transaction. |
UpdateConflictNotRecovered | Thrown when an unrecoverable error occurs in a transaction block using optimistic concurrency control. The catch block shouldn’t use a retry statement to attempt to commit the halted transaction. |
DuplicateKeyException | Thrown when a duplicate key error occurs during an insert operation. The catch block should change the value of the primary keys and use a retry statement to attempt to commit the halted transaction. |
DuplicateKeyExceptionNotRecovered | Thrown when an unrecoverable duplicate key error occurs during an insert operation. The catch block shouldn’t use a retry statement to attempt to commit the halted transaction. |
Dynamics AX 2009 introduces DuplicateKeyException. UpdateConflictException and now DuplicateKeyException are the only data exceptions that a Dynamics AX application can handle. Specifically, with DuplicateKeyException, the database transaction isn’t rolled back and the application is given a chance to recover. DuplicateKeyException
facilitates application scenarios (such as Master Planning) that
perform batch processing and handles duplicate key exceptions without
aborting the transaction in the midst of the resource-intensive
processing operation.
The following example illustrates the usage of DuplicateKeyException.
static void DuplicateKeyExceptionExample(Args _args) { MyTable myTable;
ttsbegin; myTable.Name = 'Microsoft Dynamics AX'; myTable.insert(); ttscommit;
ttsbegin; try { myTable.Name = 'Microsoft Dynamics AX'; myTable.insert(); } catch(Exception::DuplicateKeyException) { info(strfmt('Transaction level: %1', appl.ttsLevel())); info(strfmt('%1 already exists.', myTable.Name)); info(strfmt('Continuing insertion of other records')); } ttscommit; }
|
In the preceding example, the catch block handles the duplicate key exception. Notice that the ttslevel
(transaction level) is still 1, indicating that the transaction hasn’t
aborted and the application can continue processing other records.
Interoperability
The X++ language has
statements that allow interoperability (interop) with .NET CLR
assemblies and COM components. The Dynamics AX runtime achieves this
interoperability by providing Dynamics AX object wrappers around
external objects and by dispatching method calls from the Dynamics AX
object to the wrapped object.