Let me start by excusing myself for an absence of posting lately. It has been very busy recently in my private life. Becoming a father certainly makes you more prone to setting priorities 🙂
Lately I have been making several NAV2013 reports, so maybe it is time to make another post with issues you might run into, or in general even certain methods which could be convenient for you to know about.
1. Building the dataset
When creating a document layout, I was using an Integer DataItem below my lines to show some more information (in case it was needed). Using PRS, I had a function in a CodeUnit which would build my temporary record used for the DataItem, and loop it accordingly with the code below
--- Integer - OnPreDataItem --- SETRANGE(Number,1,TempRecord.COUNT); --- Integer - OnAfterGetRecord --- IF Number = 1 THEN TempRecord.FINDSET ELSE TempRecord.NEXT;
The call to fill my TempRecord was also returning a Boolean, to add to my dataset and make the table visible altogether or not (otherwise my headers would be printed).
So I added the single line call to the columns filling the TempRecord and the Dataset with my Boolean…
When running my report, I was nicely presented with 2 records of my Integer DataItem, however both times containing the last record instead of 2 different records.
Debugging showed actually looping through the TempRecord nicely, until I noticed that everytime a row for the dataset needed to be created, NAV loops through all your columns and runs the business logic if it points to a function instead of a field. Meaning that for each time, it clears my TempRecord and fills it again, positioning it at the last inserted record at the same time…
This sort of made sense of course (well, I hoped it would have cached the data of the other DataItems…), but has the logical result that I could not make the single line call in my dataset, but in code, preserving the result of the function in a Report variable and add that one to my dataset…
So remember, try to buffer everything possible in your dataset, a lot of unnecessary code could be run otherwise for each record in your dataset, instead of just the times necessary.
2. Copying Tablixes
The TempRecord above also needed to be in a table, which almost looked like the table used for my document lines, so logically I copied that one. The source table however had a lot of logic about visibility in it, which gets copied nicely. I started changing sorting, filters, rows, … from my new table until I had what I wanted and started to test again, just to notice that no data whatsoever was printed…
This took some time to figure out as well, but running through the XML of my RDLC revealed that some hidden properties of deleted rows were actually not deleted in the XML and no longer accessible from the design view.
Again, another bullet point to our reminder list: Try not to copy Tablixes , since they might get corrupted. The only way to be sure your table is created the way you want it, is to start from a blank one, which is a bit more work. But let’s be honest… it’s still pretty much manageable and not that much more work (or even less work in the end/long run)
Since Natalie asked so nicely here is a bit more information on the first problem:
I started with the following setup:
The code itself would look something like this:
GetSomeData(VAR TEMPORARY TempRecord : RecordXX) : Boolean TempRecord.RESET; TempRecord.DELETEALL; // insert multiple records into TempRecord EXIT(NOT TempRecord.ISEMPTY OR <Some boolean from setup>);
When debugging I noticed that each time a new dataset record needs to be created it start looping through your DataItem/Column setup. In this case basically for each record in the lowest DataItems it would be triggered as follow:
– Each Sales Line record
– Each Integer record
let’s say we have 1 Sales Header, 3 Sales Lines, 2 TempRecords…
The after the first SH, the report logically continues to the first SL. After the first sales line, it notices that there is not DataItem below that, meaning it should create a line in the dataset.
All fields can easily be added, however the first column is a function, so when filling the dataset, it wants to know what needs to be in the dataset AND goes through the code (clearing TempRecord, filling it up again). So far no problems, right?
Next 2 SL the same story happens, running the code AGAIN for each Sales line, which we actually do not want…
At that moment we still (again) have 2 records in the TempRecord, causing the filters in the Integer to go SETRANGE(Number,1,2) and making the DataItem loop 2 times.
The first time it enters the OnAfterGetRecord Trigger and sees Number = 1, and does a FINDSET, positioning the TempRecord on the first record. The report notices no DataItems below and start filling up another line for the dataset, thus… running the code, which clears the temprecord, and insert the 2 lines (again…) but after the 2 inserts, the record will be positioned at the last one it inserted (unless you did a findset on it in the code). Instead of printing the data of the first record in the TempRecord, it prints the data of the second record, since it was positioned on that one.
On the next TempRecord, the same story happens again. The strange thing is that TempRecord.NEXT does not give an error, since it was positioned on the last record of the temprecord…
The Report triggers the filling of the line again, which again runs the code…
In the example above the code is ran 5 times (!) where we actually only wanted it once to be triggered…
Below you will find screenshots of how it should be done instead.
So Natalie, (and everyone else)… I hope this made the problem a bit more clear?