Dynamics AX Blog - Microsoft Dynamics AX (Axapta) - Seite 36

In den letzten Jahren, in denen ich mich fast hauptsächlich mit der Entwicklung im Umfeld von Microsoft Dynamics AX (vormals Axapta) beschäftigt habe, ist das eine oder andere Code-Fragment entstanden, von dem ich mir vorstellen könnte, daß es auch für andere AX-Entwickler ganz nützlich sein könnte. Aber auch Tips und Tricks zu dem mächtigen ERP-System werde ich in dieser Kategorie präsentieren.
RSS-Feed dieser KategorieReport auf Basis eines Query erstellen
30.04.2011Microsoft Dynamics AX (Axapta)
Die Feldgruppe AutoReport einer Tabelle und deren Verwendung beim Drucken von Daten aus einem Formular heraus sollte wohl jedem Dynamics AX-Entwickler bekannt sein. Auf Basis dieser Standard-Funktionalität habe ich versucht, selbst einen Report per X++ auf Basis eines Query zu erstellen. static void createReportFromQuery(Args _args)
{ query query; report report; reportDesign reportDesign; reportRun reportRun; reportSection reportSection; sysReportRun sysReportRun; reportName reportTemplateName = 'FrontPage'; reportAutoDesignSpecs reportAutoDesignSpecs; int ds; int f; printJobSettings printJobSettings = new printJobSettings(); ; // Build query query = new query(); query.addDataSource(tableNum(vendTable)); query.dataSourceTable(tableNum(vendTable)).addRange(fieldNum(vendTable, vendGroup)).value('10'); // Add Fieldlist query.dataSourceTable(tableNum(vendTable)).addSelectionField(fieldNum(vendTable, accountNum)); query.dataSourceTable(tableNum(vendTable)).addSelectionField(fieldNum(vendTable, name)); query.dataSourceTable(tableNum(vendTable)).addSelectionField(fieldNum(vendTable, vendgroup)); // Build printJobSettings printJobSettings.setTarget(PrintMedium::Screen); printJobSettings.format(PrintFormat::PDF); printJobSettings.fileName(@"C:\Temp\TempReportFromQuery.pdf"); // Create report if( hasSecurityKeyAccess(securityKeyNum(SysDevelopment), AccessType::Edit)) { report = new report(); sysReportRun = classfactory.reportRunClass(new Args(reportstr(SysReportAuto))); sysReportRun.init(); sysReportRun.query(query); if (!sysReportRun.queryRun()) { sysReportRun.queryRun(new SysQueryRun(query)); } sysReportRun.queryRun().query().interactive(false); Report.interactive(!printJobSettings); Report.query(sysReportRun.queryRun().query()); reportDesign = report.addDesign(); reportDesign.caption("TmpReportFromQuery"); reportDesign.reportTemplate(reportTemplateName); reportDesign.orientation(printerOrientation::Auto); reportAutoDesignSpecs = reportDesign.autoDesignSpecs(); // Add body for(ds = 1;ds <= sysReportRun.queryRun().query().dataSourceCount(); ds++) { reportSection = reportAutoDesignSpecs.addSection(reportBlockType::Body, sysReportRun.queryRun().query().dataSourceNo(ds).table()); reportSection.arrangeMethod(arrangeMethod::Vertical); for(f=1;f<=sysReportRun.queryRun().query().dataSourceNo(ds).selectionCount();f++) { reportSection.addControl(sysReportRun.queryRun().query().dataSourceNo(ds).table(), sysReportRun.queryRun().query().dataSourceNo(ds).fields().field(f)); } } // Run the report reportRun = new reportRun(report); reportRun.fetch(); // Print the report if(printJobSettings) { reportRun.printJobSettings(printJobSettings.packPrintJobSettings()); } reportRun.print(); } } Das Ergebnis des obigen Codes ist ein sehr einfacher Report: |
Arbeiten mit dem aufrufenden Objekt einer Form (Caller) II
26.03.2011Microsoft Dynamics AX (Axapta)
Um in einem Objekt auf das aufrufende Objekte zuzugreifen, habe ich anhand von einigen Zeilen Code ja schon demonstriert (siehe hier und hier). Dabei hatte ich aber immer ausser Acht gelassen, daß das aufrufende Objekt ja auch eine Klasse sein kann. Nun also hier ein entsprechendes Beispiel: if (element.args() && element.args().caller() && classidget(element.args().caller()) == classnum(nameOfClass )) { nameOfClass = element.args().caller(); someValue = nameOfClass.someMethod(); } |
Praktisches Beispiel für die Verwendung des runBaseBatch-Frameworks
20.03.2011Microsoft Dynamics AX (Axapta)
Vor einiger Zeit habe ich schon einmal einen Eintrag über das runBaseBatch-Framework geschrieben, damals ging's hauptsächlich um die Aufrufreihenfolge der einzelnen Methoden und wofür einige von diesen Methoden verwendet werden können bzw. verwendet werden sollten. Nun habe ich mir basierend auf diesem Eintrag und vor allem aufgrund von Erfahrungswerten eine eigene Klasse namens tutorial_ClassWithQueryRun geschrieben, die einige oft benötigte Anforderungen vereinigt. Diese Klasse vereint folgende Fähigkeiten:
|
Beispiel für einen Query mit Gruppierung
06.02.2011Microsoft Dynamics AX (Axapta)
Der nachstehende Code zeigt wie man einen Query mit Gruppierung, Sortierung und verschiedenen Filtern aufbaut und diesen mit Hilfe eines QueryRun abarbeitet. static void tutorialQueryGroupBy(Args _args) { Query query; queryBuildDataSource queryBuildDataSource; queryBuildRange queryBuildRangeInvoiceDate; queryrun queryrun; Salesline Salesline; ; query = new query(); queryBuildDataSource = query.addDataSource(tableNum(Salesline)); // Add group by-clause queryBuildDataSource.addGroupByField(fieldNum(Salesline, custAccount)); queryBuildDataSource.addGroupByField(fieldNum(Salesline, currencyCode)); // Add fields to select-clause queryBuildDataSource.addSelectionField(fieldNum(Salesline, custAccount), SelectionField::Database); queryBuildDataSource.addSelectionField(fieldNum(Salesline, currencyCode), SelectionField::Database); queryBuildDataSource.addSelectionField(fieldNum(Salesline, lineAmount), SelectionField::Sum); queryBuildDataSource.addSelectionField(fieldNum(Salesline, createdDateTime), SelectionField::Min); // Add sort by-clause queryBuildDataSource.addSortField(fieldNum(Salesline, custAccount), SortOrder::Ascending); // Add where-clause sysQuery::findOrCreateRange(queryBuildDataSource, fieldNum(Salesline, DeliveryCountryRegionId)).value("AT, US"); sysQuery::findOrCreateRange(queryBuildDataSource, fieldNum(Salesline, createdDateTime)).value(SysQueryRangeUtil::lessThanDate(-365)); sysQuery::findOrCreateRange(queryBuildDataSource, fieldNum(Salesline, salesStatus)).value(strFmt("%1, %2", SalesStatus::Invoiced, SalesStatus::Delivered)); // Represents Select // SELECT FIRSTFAST CustAccount, CurrencyCode, SUM(LineAmount), MIN(createdDateTime) // FROM SalesLine // GROUP BY SalesLine.CustAccount, SalesLine.CurrencyCode // ORDER BY SalesLine.CustAccount ASC // WHERE ((DeliveryCountryRegionId = N'AT' OR DeliveryCountryRegionId = N'US')) // AND ((createdDateTime<'2009-07-06T22:00:00')) // AND ((SalesStatus = 3 OR SalesStatus = 2)) queryrun = new SysQueryRun(query); while(queryRun.next()) { Salesline = queryRun.get(tableNum(SalesLine)); info(strFmt("%1: %2 %3 (%4)", salesLine.CustAccount, salesLine.LineAmount, salesLine.CurrencyCode, salesLine.createdDateTime)); } } |
Clientseitige Mini-Stapelverarbeitung über die Methode setTimeOut
05.01.2011Microsoft Dynamics AX (Axapta)
Vor kurzem stand ich vor der Herausforderung, in einem Formular alle x Sekunden etwas tun zu müssen (Beispielsweise sollen alle 2 Sekunden der Inhalt einer angezeigten Datenquelle/Tabelle aktualisiert werden). Lösen kann man so etwas mit Hilfe der Methode setTimeOut, die z.B. auch von der clientseitigen Stapelverarbeitung unter Grundeinstellungen > Periodisch > Stapel > Bearbeitung verwendet wird. Dazu muss z.B. im Formular eine Methode angelegt werden, die sich selbst über die setTimeOut-Methode nach einer definierten Zeitspanne (in tausendstel-Sekunden anzugeben) aufruft: void runEvery2Seconds() { // Set a Time Out with the idle flag set to false this.setTimeOut(funcname(), 2000, false); // ...do something... dataSourceName_ds.executeQuery(); } |
SELECT-Statements mit Datumseinschränkung in AX 2009
22.12.2010Microsoft Dynamics AX (Axapta)
Im Zuge eines Upgrades einer Applikation auf Dynamics AX 2009 ist mir ein Stückchen Code über den Weg gelaufen, dessen Code-Upgrade auf den ersten Blick recht einfach sein sollte, sich aber bei genauerer Betrachtung als doch gar nicht so einfach herausgestellt hat. Und zwar gehts um ein einfaches SELECT-Statement, z.B. wie das folgende: date myDate = str2date('07.05.2010', 123); select count(recid) from salesline where salesline.createdDate == myDate; Obiges Statement soll mir einfach eine Zahl der Auftragszeilen liefern, die an einem bestimmten Tag erstellt wurden. In Dynamics AX 2009 wurde ja das Feld createdDate durch createdDateTime und einen vollständigen neuen Datentyp, der nun auch die Zeit mitspeichert, ersetzt. |
|
|
|
|
|
|
Wenn man in Dynamics AX (4.0 bzw. 2009) einmal in die Verlegenheit kommen sollte, prüfen zu müssen, ob es Tabellen mit doppelten RecIDs gibt, kann folgendes SQL-Script dabei behilflich sein:
set nocount on
declare @tableName char(100)
declare db_cursor CURSOR FOR
select name from dbo.sysobjects
where xtype = 'U'
and name <> 'ROWSTAT'
and name <> 'ROWSTATUS'
and name <> 'SQLSYSTEMVARIABLES'
and name <> 'SYSTEMSEQUENCES' -- SYSTEMSEQUENCES enthält immer doppelte RecIDs
order by name asc
-- Temporäre Tabelle aufbauen
IF OBJECT_ID(N'tempdb..#tmp_duplrecid', N'U') IS NOT NULL
begin
drop table #tmp_duplrecid
end
create table #tmp_duplrecid (tablename char(100), recordcounter bigint)
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @tableName
WHILE @@FETCH_STATUS = 0
BEGIN
-- Tabellen mit doppelten RecIds ermitteln
exec('insert into #tmp_duplrecid select ''' + @tableName + ''', COUNT(*)' +
' from ' + @tableName +
' group by RECID ' +
' having COUNT(*) > 1')
FETCH NEXT FROM db_cursor INTO @tableName
END
CLOSE db_cursor
DEALLOCATE db_cursor
set nocount off
-- Tabellen mit doppelten RecIDs
select 'Tabelle enthält doppelte RecIDs: ' + tablename
from #tmp_duplrecid