Thursday 28 April 2016

AX 2012 TFS: Solving update conflicted FK_ModelElementData_HasModelId_LayerId and XU_Update error with SQL profiler

When using AX 2012 with TFS, sometimes you'll get a cryptic error during a TFS synchronization like this:

SQL error description: [Microsoft][SQL Server Native Client 10.0][SQL Server]The UPDATE statement conflicted with the FOREIGN KEY constraint "FK_ModelElementData_HasModelId_LayerId". The conflict occurred in database "Dev5_AX2012_model", table "dbo.Model".
SQL statement: { CALL [Dev5_AX2012_model].[dbo].[XU_Update](?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) }
Cannot execute a stored procedure.

Solution : Restart the AOS Services.

Thursday 7 April 2016

Printing dynamic parameters (AX 2012 / SSRS)

In addition to parameters specified in data contracts, reports can also use queries. It’s very handy, because users can specify filters and sorting in exactly the same way as they’re used to from other places in Dynamics AX, they can use query expressions and so on.
ReportDialog

RangeSelection
A relative common request is printing parameter values on the report itself. It’s easy with parameters defined in data contracts – an expression like =Parameters!UsersToInclude.Value will do the job. But the same approach doesn’t work with dynamic parameters (that’s how query parameters get represented in SSRS).
I recommend the following approach. Use a report data provider class – very often, it’s already in place. Add a new data table to hold information about query ranges and expose it to the report. I’m using an existing table, TmpSysQuery, so we don’t have to discuss the design of the table. InprocessReport(), we extract ranges from the current query and save them to our temporary table.
Because the logic for extracting ranges from a Query object may be needed from other places as well, I’ve put it into a separate class. This is the content of the method:
///use this code
SignTestTmp.Name = query.dataSourceTable(tablenum(UserInfo)).range(1).value();
///or
public static TmpSysQuery rangesToTable(Query _query)
{
    QueryBuildDataSource    qbds;
    QueryBuildRange         queryBuildRange;
    TmpSysQuery             tmpSysQuery;
    LabelType               tableLabel;
    int                     occurrence;
    int                     dataSourceNo;
    int                     i;
 
    if (!_query)
    {
        return tmpSysQuery;
    }
 
    for (dataSourceNo = 1; dataSourceNo <= _query.dataSourceCount(); dataSourceNo++)
    {
        qbds = _query.dataSourceNo(dataSourceNo);
        if (qbds.enabled())
        {
            occurrence = SysQuery::tableOccurrence(_query, qbds.table(), dataSourceNo);
            tableLabel = tableId2pname(qbds.table()) + SysQuery::tableOccurrenceText(occurrence);
 
            for (i = 1; i <= qbds.rangeCount(); i++)
            {
                queryBuildRange = qbds.range(i);
 
                if (queryBuildRange.value() && queryBuildRange.status() != RangeStatus::Hidden)
                {
                    tmpSysQuery.clear();
                    tmpSysQuery.DataSourceNo = qbds.uniqueId();
                    tmpSysQuery.TableLabel   = tableLabel;
                    tmpSysQuery.FieldLabel   = fieldId2pname(qbds.table(), queryBuildRange.field());
                    tmpSysQuery.RangeValue   = queryBuildRange.value();
                    tmpSysQuery.insert();
                }
            }
        }
    }
 
    return tmpSysQuery;
}