Showing posts from June, 2011

Running Dynamics AX 2009 batches with a recurrence of 1 minute

In Dynamics AX batch processing, you may have specified a recurrence of 1 minute but you may have noticed that your jobs do not always gets picked up and start in 1 minute. Wondering the reason behind this? Tariq has a very nice post on this explaining the reason behind this and how you can fix this. Check it out here

canGoBatch & mustGoBatch - When to use and why?

I was posed this question today by a friend. What is the intention behind the canGoBatch() method on the RunBaseBatch class? His point was since the RunBaseBatch class was solely providing batch capabilities, what is the point of overriding the canGoBatch() and return false to hide the batch tab? I explained that there can be a scenario where you dont want to allow a user to change any settings on the batch tab. In such cases, you can make canGoBatch return false and hide the batch tab. Now he had another question, why do you not want to allow a user to change any settings on the tab? In a real world scenario, this is a typical case where you compulsorily want to ensure that your task runs in a batch. Take for example you are importing transaction files into AX from another legacy system. Now, you would want to post these on a particular date only, say end of every month. For this purpose, the administrator has setup a recurring batch job. Now an unknown user comes in, and posts a pa

How to fix - The server-side impersonated (RunAs) session tried to invoke a method that is available for client-side processing only

Recently, I was asked to help with an issue in one of our development environments. The scenario was that we were importing bank statements in text format into Dynamics AX and then creating a log file on the system. I was told that this code was working fine but all of a sudden they were seeing the below error when running the process in batch. The server-side impersonated (RunAs) session tried to invoke a method that is available for client-side processing only. The above error occurs only when a code running on Server tries to call a code which is bound to run on client. So whats the bigs issue, you will ask? Why cant the server code call the client code. This will be a problem only when there is no open client. For example, code is running in batch on the server and there is no open client. To fix this, they had overridden the runsImpersonated() method and were explicitly returning false. I explained them that, this meant that their batch code will run on the client instead of the

How to add empty ranges in query

In Dynamics AX programming, a common mistake I have seen when it comes to query ranges is passing an empty string value to the range. The developer here is expecting it to show all the records where the range field is empty. Instead, what we get is all records without the range being applied. As baffling as it may seems, it is easily explainable. The query engine in Dynamics AX, will not add a range if you don’t specify a value or if you specify an empty string because an empty string is treated as no value. So the following code will result in this SQL statement, query = new Query(); qbds = query.addDataSource(tableNum(ProjTable)); qbr = qbds.addRange(fieldNum(ProjTable, Name)); qbr.value(''); Select first fast * from ProjTable; But what was expected was something like, Select first fast * from ProjTable where Name == ''; So to work around this issue, use the SysQuery::valueEmptyString() static method which parses the empty strings correctly so that it

rowCount() method on table buffers.

At first glance, this method looks like that it will return the number of rows selected on a table. But that is not the case. If we run the following lines, the result will be always -1 select custTable where custTable.custGroup=='10'; print custTable.rowCount(); The issue is that this method is to be used only with set based operations on the database. So, if you are using insert_recordset, update_recordset or delete_from, the rowCount() method will return the number of rows created, updated or deleted. Here is a sample job that shows this in action. static void rowCountJob(Args _args) { CustTable custTable; MyTable myTable; ; ttsbegin; insert_recordset myTable(AccountNum, PartyId, CustGroup, Currency) select AccountNum, PartyId, CustGroup, Currency from custTable where custTable.CustGroup== '10'; // Prints 13 as 13 records with custGroup == 10 were inserted from CustTable print myTable.Row

selectRefRecord() method on table buffers.

The selectRefRecord() on table buffers can be used to retrieve the reference record accociated with a particular field. The underlying implementation of the method takes care of selecting the correct record based on the relation between the referenced field and the parent table. Let us take an example. Suppose we want to select the CustGroup associated with a SalesTable record. The normal way someone will do that is, SalesTable salesTable; CustGroup custGroup; ; select firstonly salesTable; custGroup = CustGroup::find(salesTable.CustGroup); print custGroup.CustGroup; print custGroup.Name; The same can be achieved using the selectRefRecord() method as well, SalesTable salesTable; CustGroup custGroup; ; select firstonly salesTable; custGroup = salesTable.selectRefRecord(fieldnum(SalesTable, CustGroup)); print custGroup.CustGroup; print custGroup.Name; Both the implementation has the same the same number of lines of cod