Dynamics AX Blog - Dynamics AX 2009 - Seite 13

RSS-Feed dieser Version
Zertifizierungsprüfung Microsoft Dynamics AX 2009 Trade & Logistics
07.12.2009In eigener Sache
Heute morgen habe ich eine weitere Microsoft Zertifizierungsprüfung - der genaue Titel lautete Microsoft Dynamics AX 2009 Trade & Logistics - erfolgreich abgelegt. |
PageFooter sind nicht immer dort, wo sie sein sollten
04.12.2009Microsoft Dynamics AX (Axapta)
Ich kenne kein einziges AX-Projekt, in dem nicht zumindest einer der Berichte Auftragsbestätigung, Ausgangslieferschein oder Ausgangsrechnung angepasst worden sind. Und deshalb stolpere ich auch immer wieder über das selbe Problem: Man erweitert einen Bericht (Report) um einen PageFooter, der aber nicht auf jeder Seite angedruckt werden soll. |
Vorsicht beim Mandanten duplizierenDaß man einen Mandanten/Unternehmen duplizieren kann, ist bekannt. Die Erfahrung der vergangenen Wochen hat mich in dem Zusammenhang folgendes gelehrt:
Um sicherzustellen, daß man der einzige Benutzer im System ist, sollte man alle anderen deaktivieren. Außerdem sollte man vor dem Kopiervorgang ein Datenbank-Backup anlegen und nach der erfolgten Aktion den Quell- und Zielmandant hinsichltich doppelter Datensätze vergleichen. Hierfür kann man sich der Funktion "Anzahl der Datensätze" bedienen. |
Alle Felder einer Tabelle auflisten
22.11.2009Microsoft Dynamics AX (Axapta)
Kurzes Codebeispiel, wie man alle Felder einer Tabelle auflistet: static void ListFieldOfTable(Args _args)
{ dictTable dictTable; int currFieldId = 0; counter c = 0; ; dictTable = new dictTable(tableNum(custtable)); do { currFieldId = dictTable.fieldNext(currFieldId); info(dictTable.fieldName(currFieldId)); c++; } while (c < dictTable.fieldCnt()); }
|
Arbeiten mit dem aufrufenden Objekt einer Form (Caller)Nachstehende Methode enthält einige Snippets, die in einem Formular verwendet werden können, um in Dynamics AX diverse Funktionen/Methoden des Aufrufenden Objektes aufzurufen. Ändert man element.args() auf z.b. _args und übergibt der Methode diese als Parameter, kann die selbe Logik auch aus einer Klasse heraus verwendet werden.
void workWithCallingRecord()
{
common common;
object object;
formDataSource formDataSource;
formRun formRun;
inventDim inventDim;
salesTable salesTable;
int i;
;
// Call method from calling record
if( element.args() &&
element.args().record() )
{
common = element.args().record();
if(common.isFormDataSource())
{
info(tableId2Name(common.TableId));
if(formDataSourceHasMethod(common.dataSource(), identifierStr("someMethod")))
{
object = common.dataSource();
object.someMethod();
}
}
}
// Call method from calling form
if(element.args() && element.args().caller() && element.args().caller().handle() == className2Id('formRun'))
{
formRun = element.args().caller();
if(sysFormRun::hasMethod(formRun, identifierStr("someFormMethod")))
{
object = formRun;
object.someFormMethod();
}
}
// Get value from calling record
if( element.args() &&
element.args().record() )
{
common = element.args().record();
if(common.TableId == tableNum(salesTable))
{
info(common.(fieldNum(salesTable, salesId)));
}
}
// Get value from calling datasource (form with multiple datasources)
if(element.args() && element.args().caller() && element.args().caller().handle() == className2Id('formRun'))
{
formRun = element.args().caller();
for (i = 0; i <= formRun.dataSourceCount(); i++)
{
formDataSource = formRun.datasource(i);
if (formDataSource && formDataSource.table() == tablenum(inventDim)) // Search for specific table
{
inventDim = formDataSource.cursor();
break;
}
}
if(inventDim)
{
info(inventDim.InventLocationId);
}
}
// Change data in calling datasource
if(element.args() && element.args().caller() && element.args().caller().handle() == className2Id('formRun'))
{
formRun = element.args().caller();
for (i = 0; i <= formRun.dataSourceCount(); i++)
{
formDataSource = formRun.datasource(i);
if (formDataSource && formDataSource.table() == tablenum(salesTable)) // Search for specific table
{
salesTable = formDataSource.cursor();
break;
}
}
if(salesTable)
{
// Update data
salesTable.PurchOrderFormNum = "Some value";
salesTable.update();
}
}
// Refresh calling datasource
if( element.args() &&
element.args().record() )
{
common = element.args().record();
if(common.isFormDataSource())
{
formDataSource = common.dataSource();
formDataSource.research(true);
}
}
} |
Dynamics AX mit einem bestimmten Windowslogin starten
08.11.2009Microsoft Dynamics AX (Axapta)
Gegenüber früheren Versionen von Dynamics AX hat man - dank Integration des Active Directories - in AX 2009 kaum Möglichkeiten, die Anwendung als ein bestimmter Benutzer zu starten. Gerade dies ist aber notwendig, wenn man z.B. Änderungen in den Sicherheitseinstellungen/Berechtigungen überprüfen möchte. Für solche Fälle habe ich mir eine Batch-Datei (*.bat) geschrieben, die mir eine lokale AX-Installation mit einem bestimmten Windows-Login startet. Diese Batch-Datei öffnet ein Windows-Kommandozeilen-Fenster in welchem man zur Eingabe des Windows-Passworts aufgefordert wird. runas /user:domain\username "C:\Programme\Microsoft Dynamics AX\50\Client\Bin\Ax32.exe "C:\Programme\Microsoft Dynamics AX\50\MyConfigurationfile.axc"" Wenn man diese Befehlszeile direkt in der Eingabeaufforderung eingeben will, muss man den Befehl wie folgt leicht abwandeln: runas /user:domain\username "C:\Programme\Microsoft Dynamics AX\50\Client\Bin\Ax32.exe \"C:\Programme\Microsoft Dynamics AX\50\MyConfigurationfile.axc\"" Muss man ausser der Konfigurationsdatei noch weitere Parameter übergeben, kann man die Batch-Datei wie folgt erweitern: runas /user:domain\username "C:\Programme\Microsoft Dynamics AX\50\Client\Bin\Ax32.exe "C:\Programme\Microsoft Dynamics AX\50\MyConfigurationfile.axc" -aol=var -aolcode=j+eA4566458bsZReSO1Q==" Der selbe Befehl sähe, wenn man ihn über die Eingabeaufforderung eingeben wollte, wie folgt aus: runas /user:domain\username "C:\Programme\Microsoft Dynamics AX\50\Client\Bin\Ax32.exe \"C:\Programme\Microsoft Dynamics AX\50\MyConfigurationfile.axc\" -aol=var -aolcode=j+eA4566458bsZReSO1Q==" Alternativ dazu kann man sich auch der hier beschriebenen Lösung bedienen. Übrigens: Sollte die Konfigurationsdatei auf einem Netzlaufwerk liegen, so sollte man bei der Angabe des Dateipfades nicht dessen Laufwerksbuchstaben verwenden, sondern den vollen UNC-Pfad. Denn möglicherweise hat der Benutzer, mit dem ich die Applikation starten möchte, den einzelnen Netzwerklaufwerken andere Laufwerksbuchstaben zugewiesen als man selbst ;-) |
|
|
|
|
|
|
Kurzer Eintrag in eigener Sache:
Nachstehend Beispiele für den Zugriff auf die AX-Datenbank per SQL-Statement, diese Zugriffe müssen im übrigen immer serverseitig erfolgen (runOn-Property).
Beispiel für ein SELECT-Statement
public void run() { Connection connection = new Connection(); Statement stmt = connection.createStatement(); sqlStatementExecutePermission sqlStatementExecutePermission; str sqlStmt; resultSet resultSet; ; sqlStmt = "SELECT accountNum, name, creditMax FROM custTable;"; sqlStatementExecutePermission = new SqlStatementExecutePermission(sqlStmt); sqlStatementExecutePermission.assert(); resultSet = stmt.executeQuery(sqlStmt); while (resultSet.next()) { info(strFmt("%1 %2 %3", resultSet.getString(1), resultSet.getString(2), resultSet.getReal(3))); } CodeAccessPermission::revertAssert(); }Übrigens: Wenn folgender Fehler beim Abfragen des resultSets auftritt, kann die Ursache ein ungültiges SQL-Statement sein!