Personalized Community is here!
Quickly customize your community to find the content you seek.
Choose your path Increase your proficiency with the Dynamics 365 applications that you already use and learn more about the apps that interest you. Up your game with a learning path tailored to today's Dynamics 365 masterminds and designed to prepare you for industry-recognized Microsoft certifications.
Visit Microsoft Learn
2020 Release Wave 2Discover the latest updates and new features to Dynamics 365 planned through March 2021.
Release overview guides and videos Release Plan | Preview 2020 Release Wave 2 TimelineWatch the 2020 Release Wave 1 virtual launch event
Ace your Dynamics 365 deployment with packaged services delivered by expert consultants. | Explore service offerings
Connect with the ISV success team on the latest roadmap, developer tool for AppSource certification, and ISV community engagements | ISV self-service portal
The FastTrack program is designed to help you accelerate your Dynamics 365 deployment with confidence.
FastTrack Program | Finance TechTalks | Customer Engagement TechTalks | Upcoming TechTalks
I'm building a RDP based SSRS report and I'm facing an issue.
In my DP class, I use 2 table to get my data (classical Header + Lines). The problem is if I set my both table as temp table or both as Regular, my report is not displaying all datas. If I set 1 table as temp and the other as regular, everythink is working fine.
My questions are :
Is it possible to use 2 temp table with a RDP extending SRSReportDataProviderBase ? (prefered solution, easier and faster to build)
Or do I need to extend SrsReportDataProviderPreProcess and manage this with regular table and transId as SalesOrderReport for exemple ?
thank you for you advice,
AX 2012 R2
Yes, using InMemory tables is how it should be done. I'm sure you would find many examples in the standard application.
Therefore your problem must lie somewhere else.
How do you use the data in the form? What if create a simple design with two tables - first print everything from the headers data set and then the lines data set (without trying to relate them)? If you get the data, you'll know that the RDP class is fine and the problem in your actual design. If it doesn't work either, we'll at least know that and we'll have to think more about the cause.
Thank you Martin for your fast answer.
I did a misstake when I expose my case. My 2 tables are not related.
Header table has only one record anyway.
How do you use the data in the form?
I think you wanna say "report" instead of "form" ? Or I misunderstood your explanation.
My design is already as simple as you said.
Note that I've noticed when testing with both table as Regular that some fields in one of the table are not filled.(EDIT : I forgot I commented my code. It work fine with regular table too) But if I use the 1 temp 1 regular combo, all fields are filled fine.
Again thank you for helping and sorry for bad english
I noticed that the temp table which is not filled is random. Sometime it's the HeaderTable, sometimes it's the LinesTable. I really dont understand what's happening.
Here is a job I use to test my RDP. got the same problem when executing the job or the report. So the problem might be in my classes.
static void job11(Args _args)
contract = new DLZvendorReminderContract();
contract.parmDelayDate(mkDate(14, 2, 2020));
rdp = new DLZvendorReminderDP();
headerData = rdp.getDLZVendorReminderHeaderTmp();
while select headerData
info(strFmt("%1 – %2", headerData.ReminderID, headerData.IntroMessage));
lineData = rdp.getDLZVendorReminderLineTmp();
while select lineData
info(strFmt("%1 - %2", lineData.PurchId, lineData.LineNumber));
Sorry, I meant a report. All right, so now we know that the problem isn't anywhere in the report design, but it's in processReport(). Therefore you should debug processReport().
Here is my DP simplified as much as possible.
class DLZvendorReminderDP extends SRSReportDataProviderBase
DlvDate delayDate, projectedDelayDate;
public DLZvendorReminderHeaderTmp getDLZVendorReminderHeaderTmp()
public DLZvendorReminderLineTmp getDLZVendorReminderLineTmp()
public void processReport()
public void setDataTest()
vendorReminderHeaderTmp.ReminderID = 'ReminderID';
vendorReminderHeaderTmp.ReminderDate = today();
vendorReminderHeaderTmp.CompanyName = 'CompanyName';
vendorReminderHeaderTmp.CompanyAddress = 'CompanyAddress';
vendorReminderHeaderTmp.CompanyPhone = 'CompanyPhone';
vendorReminderHeaderTmp.CompanyTeleFax = 'CompanyTeleFax';
vendorReminderHeaderTmp.CompanyEmail = 'CompanyEmail';
vendorReminderHeaderTmp.CompanyURL = 'CompanyURL';
vendorReminderHeaderTmp.CompanyCoRegNum = 'CompanyCoRegNum';
vendorReminderHeaderTmp.CompanyEnterpriseNumber = 'CompanyEnterpriseNumber';
vendorReminderHeaderTmp.PrintLogo = NoYes::No;
vendorReminderHeaderTmp.CompanyContactName = 'CompanyContactName';
vendorReminderHeaderTmp.VendorContactName = 'VendorContactName';
vendorReminderHeaderTmp.VendName = 'VendName';
vendorReminderHeaderTmp.VendAddress = 'VendAddress';
vendorReminderHeaderTmp.IntroMessage = 'IntroMessage';
vendorReminderHeaderTmp.OutroMessage = 'OutroMessage';
recInsList = new RecordInsertList(tableNum(DLZvendorReminderLineTmp));
for (i = 1; i <= 20; i++)
vendorReminderLineTmp.PurchId = strFmt('PurchId %1', i);
vendorReminderLineTmp.LineNumber = i;
vendorReminderLineTmp.ItemId = strFmt('ItemId %1', i);
vendorReminderLineTmp.InventDimStr = 'InventDimStr';
vendorReminderLineTmp.ItemNameAlias = 'ItemNameAlias';
vendorReminderLineTmp.ExternalItemNum = 'ExternalItemNum';
vendorReminderLineTmp.QtyOrdered = i;
vendorReminderLineTmp.RemainPurchPhysical = i;
vendorReminderLineTmp.PurchUnit = 'PurchUnit';
vendorReminderLineTmp.DeliveryDate = today();
vendorReminderLineTmp.ConfirmedDlv = today();
vendorReminderLineTmp.DLZPurchLineDelayStatus = DLZPurchLineDelayStatus::Delay;
My both table are tempDB and here is my result:
What i expect: (1 tempDB 1 regular)
Hmm, so you're now using TempDB tables? Can you please confirm whether you're using only TempDB tables (not InMemory temporary tables) from the beginning?
I tried with InMemory too but actualy, I confirm using tempDB.
Both types (InMemory and TempDB) should work, but it's good to know which case we're discussion.
I think the problem is related to the RecordInsertList. You return data from vendorReminderLineTmp buffer, but you've never inserted anything there. You just use the variable to provide input for RecordInsertList.
Maybe it can be done by passing the temporary buffer to the 7th argument of RecordInsertList's constructor, but I would first ask myself whether using RecordInsertList has any benefit in this case.
You return data from vendorReminderLineTmp buffer, but you've never inserted anything there. You just use the variable to provide input for RecordInsertList.
I dont get it. What's wrong with RecordInsertList ? I've always used it this way.
But anyway, the problem persist even if I use simple Insert().
Ok after cleaning all cache, restart AOS and SSRS, it's seems that it's working while inserting record by record.
My new questions are :
Does TempDB / InMemory table support RecordInsertList ?
Is my utilisation of RecordInsertList correct ? If yes, how can I identify in the future that's RecordInsertList causing problem ? (refering to the fact that worked with regular table)
whether using RecordInsertList has any benefit in this case.
Just going for a single trip database insert so it's a benefit, no ?
Can you show your current code? How do you test it? The statement that the kernel of AX is broken and insert() method doesn't work at all on temporary tables doesn't sound likely.
The assumption that RecordInsertList always reduces the number of DB calls isn't precise. In certain cases, it still processes records one by one (if insert() method is overriden, InMemory table is used and so on). Therefore checking if there is any benefit still makes sense.
For completeness, RecordInsertList often makes more than just one DB call - it would require holding all records in memory. Instead, it inserts records in batches.
The statement that the kernel of AX is broken and insert() method doesn't work at all on temporary tables doesn't sound likely.
I've edited my previous message, I forgot to refresh some caches, it works fine with Insert().
Plus, I followed your advice to use the 7th argument in construct of RecordInsertList and that totally works !
recInsList = new RecordInsertList( tableNum(DLZvendorReminderLineTmp),
Thank you for precision about RecordInsertList. Last question, I promise. I dont really understand why this 7th argument is necessary ? What's different with a Regular table that make this argument required ?
Anyway, thank you very much Martin for your precious time and your help.
Working with temporary tables is a bit confusing, because it looks almost the same as with regular tables but it actually works in quite a different way.
If you insert data to a regular table, everybody can see it. All you need to know to query the data is the table name. You ask the DB server for the content of the table, and the server returns it to you.
If you insert data to a temporary table, you get a completely new container for data (a memory location, a file on disk or a new table in TempDB database). And the variable in X++ holds a reference to this container. Nobody can access the data without this reference.
If you create two variables for VendorReminderLineTmp table, you have to separate containers. If you insert a record to one buffer, you want see it in the other buffer, because they point to different memory locations, files or TempDB tables. An exception is if you explicitly make them point to the same container. In your own code, you use setTmpData() (for InMemory tables) or linkPhysicalTableInstance() (for TempDB tables). Then you can insert data to either buffer and you can retrieve it from both.
This is also what happens with RecordInsertList. You're giving it a refer to a temporary data set that the class should use, instead of using a new independent one.
Business Applications communities