In AX 2009, I have some code that runs a stored procedure on the same database, and loops round the results. This works without any problems (I can use the InfoLog or the debugger to see the values). This code is being run in a class called from a Form.
What I would like to do is add the results from the stored procedure into an AX table. When I use TTSBegin inside the loop, or even outside the loop, but still in the same method, I get these error messages:
Cannot execute the required database operation. The SQL database has issued an error.
One or more critical STOP errors have occurred. Use the error messages below to guide you or call your administrator.
Stack trace: An error occurred while starting TTS transaction.
Does anyone know how I could fix it?
Thanks so much!
Edit: Here is the code that is causing the problem. As soon as the code execution reaches TTSBegin, I get a stack trace error.
public void run()
{
Connection connection;
Statement statement;
str query;
Resultset resultSet;
str storedProcedureName, parameterValue;
str QtyStr;
SalesQty salesQty;
int qty;
ItemId itemID;
int sumItemCount; // Item summary variable
EventInbox inbox;
int counter;
;
// create connection object
connection = new Connection();
// create statement
statement = connection.createStatement();
storedProcedureName = "usp_AX_GetBuildPlanDetails";
parameterValue = "030623";
// Define the SQL statement
Query = strFmt("EXEC %1 %2", storedProcedureName, parameterValue);
// assert SQL statement execute permission
new SqlStatementExecutePermission(query).assert();
// when the query returns result,
// loop all results for processing
//BP Deviation documented
resultSet = statement.executeQuery(query);
try
{
while (resultSet.next())
{
// (1) Read in the ItemID from SQL.
itemID = resultset.getString(2);
infolog.add(Exception::Info, strfmt("Item ID: %1", itemId));
// (4) Gather the QTY for that week.
QtyStr = resultset.getString(11);
qty = str2int(QtyStr);
salesQty = abs(qty); //Use absolute QTY value to account for accidental negative values.
// Increase the item counter.
sumItemCount++;
}
// This EventInbox code (for the alerts) causes a Stack Trace error with the TTSBegin code.
// Create EventInbox event to track summary of operation
ttsbegin;
inbox.initValue();
inbox.ShowPopup = NoYes::Yes;
inbox.Subject = "Weekly Forecast Import";
inbox.Message = strfmt("%1 forecast items processed.", sumItemCount);
inbox.AlertedFor = "Weekly Forecast Import Results";
inbox.SendEmail = NoYes::Yes;
inbox.UserId = curuserid();
inbox.TypeId = Exception::Info;
inbox.AlertTableId = tablenum(ForecastSales);
inbox.AlertFieldId = fieldnum(ForecastSales, ItemId);
inbox.TypeTrigger = EventTypeTrigger::RecordInsert;
inbox.CompanyId = curext();
inbox.InboxId = EventInbox::nextEventId();
inbox.AlertCreatedDateTime = DateTimeUtil::getSystemDateTime();
inbox.insert();
ttscommit;
infolog.add(Exception::Info, strfmt("Forecast import complete for %1 items. Run the forecast scheduling process to replan.", progressCounter));
}
catch (Exception::Deadlock)
{
retry;
}
catch (Exception::Error)
{
ttsabort;
ttsbegin;
inbox.initValue();
inbox.ShowPopup = NoYes::Yes;
inbox.Subject = "Weekly Forecast Import";
inbox.Message = "Error importing Weekly Forecast.";
inbox.AlertedFor = "Weekly Forecast Import Failure";
inbox.SendEmail = NoYes::Yes;
inbox.UserId = curuserid();
inbox.TypeId = Exception::Error;
inbox.AlertTableId = tablenum(ForecastSales);
inbox.AlertFieldId = fieldnum(ForecastSales, ItemId);
inbox.TypeTrigger = EventTypeTrigger::RecordInsert;
inbox.CompanyId = curext();
inbox.InboxId = EventInbox::nextEventId();
inbox.AlertCreatedDateTime = DateTimeUtil::getSystemDateTime();
inbox.insert();
ttscommit;
}
endlengthyoperation();
// limit the scope of the assert call
CodeAccessPermission::revertAssert();
}
Direct SQL activity can be tricky, so you sometimes have to play around to get it right. Below are 3 things you can try.
It looks like you should use
UserConnectioninstead ofConnection, where the former is used for operations that should stay in the same transaction scope and the latter is more for direct SQL operations irrespective of user. This might explain your transaction error. If you move yourCodeAccessPermission::revertAssert();before yourttsbegin, I'd be curious if that solves it.1
I suspect something like this in your
catchblock could solve too:The
ttsAbortisn't necessary in the catch block as the system aborts the transaction automatically. It is needed forConnection/UserConnectionthough I think.2
With your existing code, some things you can try in various places in your code:
3
I think changing to a
UserConnectionmakes more sense and sharing the connection. I rewrote this without your actual environment, so there may be minor mistakes that you need to tweak. Try this method: