If Sort-Field is empty sort by another field

At work we recently discussed a customer requirement regarding sorting of a SalesTable data set in Dynamics Ax. The requirement was to sort by ShippingDateConfirmed. If the order has no confirmation date yet, use the ShippingDateRequested instead.

If exists sort by Shipping Date Confirmed otherwise by Shipping Date Requested

There are several ways to implement this requirement. Depending on the technology you can use SQL code, computed columns in Dynamics Ax 2012+ or a union query in AX 2009.

SQL: Select CASE

The easiest way to achiev the goal is using pure SQL code where you can define a new column within the select statement and use it for sorting. Here is an example:

SELECT 
SalesId, SalesName, 
ShippingDateRequested, ShippingDateConfirmed, 
CASE 
WHEN ShippingDateConfirmed = '1900-01-01 00:00:00.000' 
THEN ShippingDateRequested 
ELSE ShippingDateConfirmed 
END 
AS ErpSortField
FROM SalesTable
WHERE DataAreaId = 'CEU'
ORDER BY ErpSortField

The result in SQL Server Management Studio for a Dynamics Ax 2009 database looks like this:

SELECT CASE WHEN .. THEN .. ELSE .. END in SQL
SELECT CASE WHEN .. THEN .. ELSE .. END in SQL

You may use such a SQL query as data source for an SSRS report

SSRS Report based on AX 2009 Sales Order
SSRS Report based on AX 2009 Sales Order

Dynamics 365 F/SCM: Computed Column

Since AX 2012 we can use computed columns in views. One way to address this requirement is to create a column that contains the same CASE – WHEN SQL Statement. To do so create a new view based on the SalesTable. Add a new static method:

private static server str compColShippingDate()
{
  #define.ViewName(MBSSalesTableView)
  #define.DataSourceName("SalesTable")
  #define.FieldConfirmed("ShippingDateConfirmed")
  #define.FieldRequested("ShippingDateRequested")
  str sReturn;
  str sRequested, sConfirmed;
  DictView dv = new DictView(tableNum(#ViewName));

  sRequested = dv.computedColumnString(
                   #DataSourceName,
                   #FieldRequested,
                   FieldNameGenerationMode::FieldList);
  sConfirmed = dv.computedColumnString(
                   #DataSourceName,
                   #FieldConfirmed,
                   FieldNameGenerationMode::FieldList);

  sReturn = "CASE WHEN " 
          + sConfirmed + " = '1900-01-01 00:00:00.000' THEN " 
          + sRequested + " ELSE " + sConfirmed + " END";

  return sReturn;
}

Add a computed column to the view and set the method as view method. Build and synchronize.

View with computed column in Dynamics 365 Finance
View with computed column in Dynamics 365 Finance

This will result in the following SQL definition in the AXDB:

Generated SQL view code in AxDB
Generated SQL view code in AxDB

Use the view as data source in form:

View in Dynamics 365 F/SCM form
View in Dynamics 365 F/SCM form

Dynamics AX 2009: Union Query

Older versions of Dynamics AX link 2009 computed columns were not supported. One workaround is to use a UNION Query.

First create a new view called ERPSalesTableConfirmed. Set the SalesTable as data source. Add a range based on the ShippingDateConfirmed field and set the range value to != ” (i.e. not empty). Add a view field based on the ShippingDateConfirmed and call it ERPSortField. This view will return all SalesTable records with a confirmed shipping date and a new field with the value in it.

SalesTable with confirmed shipping date
SalesTable with confirmed shipping date

Second, create a new view called ERPSalesTableRequested. Set the SalesTable as data source. Add a range based on the ShippingDateConfirmed and set the range value to = ” (i.e. empty). Add a view field based on the ShippingDateRequested and call it ERPSortField. This view will return all SalesTable records without a confirmed shipping data and use the ShippingDateRequested for the ERPSortField.

SalesTable with requested shipping date
SalesTable with requested shipping date

Next, create a query called ERPSalesTableSort. Set the query type to UNION. Add both views as data source. The execution of this query will return all SalesTable records. If the sales order was confirmed, the ERPSortField will contain the ShippingDateConfirmed value, otherwise the ERPSortField will contain the ShippingDateRequested.

UNION query in Dynamics AX 2009
UNION query in Dynamics AX 2009

Finally, create a new view called ERPSalesTableSort based on the query with the same name. Use all fields you like to see and the ERPSortField.

Dynamics AX 2009 view based on UNION query
Dynamics AX 2009 view based on UNION query

Open the view. The result is a SalesTable dataset that can be sorted on the confirmed shipping date, and if the confirmed date is not present sorted by the requested date.

Sort SalesTable in Dynamics AX 2009 by confirmed or requested shipping date
Sort SalesTable in Dynamics AX 2009 by confirmed or requested shipping date

Using Bing Maps app in Excel to visualize inventory on hand data

This video shows how to use Bing Maps app in Excel to visualize on-hand data

Receive large texts via AIF

One of our customer’s business partner transmits data as XML file. However, they did not make it to use a structured xml document service, but send a string that (in most cases) contains a valid xml document. Therefore we’ve setup an AIF service, using a class that takes one str parameter called _txt and stores it at a memo field.

public void storeText(str _text)
{
    AifBigData bigData;
    ;
    bigData.Text = _text;
    bigData.insert();
}

However, the business partner recently told us they get an error message while transmitting data to the AIF service telling them the transmitted data is too large. We were able to reproduce the issues by calling the service using a larger random-generated text.

class Program
{
    static void Main(string[] args)
    {
        var client = new BigData.BigDataServiceClient();
        client.ClientCredentials.Windows.ClientCredential = new
         System.Net.NetworkCredential("user","pass123","domain");

        // works fine
        client.storeText("Hello World");

        // fails 😦
        string txt = GenerateBigText();
        client.storeText(txt);
    }

    private static string GenerateBigText()
    {
        var random = new Random(); 
        var sb = new StringBuilder();
        for (int i = 0; i < 61440; i++)
        {
            char c =  (char)random.Next(65, 122);
            sb.Append(c);
        }

        return sb.ToString();
    }
}

The second call results in an exception

The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://insideax.at/bigdata:_text. The maximum string content length quota (8192) has been exceeded while reading XML data. This quota may be increased by changing the MaxStringContentLength property on the XmlDictionaryReaderQuotas object used when creating the XML reader.

However, the exception is well explained and contains a solution proposal to set the MaxStringContentLength

Go to Basic > AIF > Services > Button Configure

image

Select Binding > basicHTTPBinding > ReaderQuotas > MaxStringContentLenght and set e.g. 2147483647

image

Save and generate the .NET artifacts. Open windows explorer and navigate to the AIF virtual directory e.g. C:\Program Files\Microsoft Dynamics AX\50\AifWebServices . Select the web.config and open it with internet explorer. Make sure the MaxStringContentLength value is set

image

With this configuration the service call will work and a large text message is stored properly in Dynamics AX

image

MB6-820 Dynamics AX 2009 Installation & Configuration

I’ve passed the MB6-820 Dynamics Ax 2009 Installation & Configuration exam. Questions are fair and with some experience installing AX in different environments you have a good chance to pass the exam with a high score.

Dynamics Certifications

image

Windows and SQL Server Certifications

image

Enterprise Portal Custom Filter Error after a short time

Again I experienced a strange behavior within Dynamics AX 2009 Enterprise Portal. I’ve created a AxGridView using an AxDataSource connected to a DataSet in Dynamics AX. The DataSet holds a setFilter method to set values on some QueryBuildRanges. Moreover I’ve create a button in my AxUserControl Webpart that invokes the setFilter method with some values.

protected void SearchButton_Click(object sender, EventArgs e)
{
   string value1 = TextBox1.Text;
   string value2 = TextBox2.Text;
   AxDataSourceMyTable.GetDataSet().DataSetRun.AxaptaObjectAdapter.Call  
    (“setFilter”,value1,value2);
}

public void setFilter(str _value1, str value2)
{;
   qbrSomeField.value(_value1);
   qbrAnotherField.value(_value2);
   MyTable_DS.executeQuery();
}

This implementation worked fine the first time using the webpart. However, after a very short time I got an error telling me that no Business Connector Session was found.

Microsoft.Dynamics.Framework.BusinessConnector.Session.Exceptions.NoKernelSessionException

First I thought of some kind of timeout and played with IIS settings. But Google found this discussion where it is explained that Dynamics AX deletes the QueryBuildRange objects after a very short time, and therefore the call fails. The solution is to use SysQuery::findOrCreateRange .

public void setFilter(str _value1, str value2)
{
   QueryBuildDataSource qbds;
   ; 
   qbds = MyTable_DS.query().dataSourceTable(tableNum(MyTable))
   SysQuery::findOrCreateRange(qbds,fieldNum(MyTable,Field1)).value(_value1);
   SysQuery::findOrCreateRange(qbds,fieldNum(MyTable,Field2)).value(_value2);
   MyTable_DS.executeQuery();
}