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

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 KategorieErstellen einer Entität - beispielsweise eines Debitoren - per Code unter Verwendung von AX<Table>-Klassen
12.11.2013Microsoft Dynamics AX (Axapta)
Folgender Job soll veranschaulichen, wie man unter Verwendung von sog. AX<Table>-Klassen Entitäten in Dynamics AX per Code anlegen kann, ohne dabei - wie in diesem Beitrag beschrieben - direkt in die Tabellen zu schreiben.
Nachteile:
static void CreateCustomerAXClass(Args _args) { AxCustTable axCustTable; AxDirPartyTable AxDirPartyTable; CustTable CustTable; DirPartyTable DirPartyTable; AccountNum accountNum = "4711"; Name name = "Debitor 4711"; currencyCode currencyCode = "EUR"; custGroupId custGroupId = "DINL"; taxGroup taxGroup = "DINL"; languageId languageId = "de-AT"; ttsBegin; // Create or update Customer axCustTable = axCustTable::construct(); axCustTable.validateInput(true); axCustTable.continueOnError(true); // Validate fields without stopping error CustTable = CustTable::find(accountNum, true); if(CustTable) { axCustTable.custTable(CustTable); // Don't use this for new records to get initValue() called } axCustTable.parmAccountNum(accountNum); axCustTable.parmCustGroup(custGroupId); axCustTable.parmTaxGroup(taxGroup); axCustTable.parmCurrency(currencyCode); axCustTable.save(); // Create or update Global address book AxDirPartyTable = AxDirPartyTable::construct(); AxDirPartyTable.validateInput(true); AxDirPartyTable.continueOnError(true); // Validate fields without stopping error DirPartyTable = DirPartyTable::findRec(axCustTable.custTable().Party, true); if(DirPartyTable) { AxDirPartyTable.dirPartyTable(DirPartyTable); } AxDirPartyTable.parmName(name); AxDirPartyTable.parmLanguageId(languageId); AxDirPartyTable.save(); ttsCommit; } |
Erstellen einer Entität - beispielsweise eines Debitoren - per Code
12.11.2013Microsoft Dynamics AX (Axapta)
Beim Start eines AX-Projektes ist die Übernahme von Daten aus Vorsystemen oft ein Thema. Mittlerweile gibt es zahlreiche Möglichkeiten dies zu tun - beispielswiese das Data import Export Framework (DIXF), ich möchte in diesem Beitrag aber auf die einfachste Variante eingehen, um eine Entität - im Beispiel einen Debitoren - in Dynamics AX per Code anzulegen. static void CreateCustomerSimple_I(Args _args) { custTable custTable; DirPartyTable dirPartyTable; AccountNum accountNum = "8888"; currencyCode currencyCode = "EUR"; custGroupId custGroupId = ""; taxGroup taxGroup = ""; // Create or update Customer ttsBegin; CustTable = CustTable::find(accountNum, true); // Find existing record for update custTable.AccountNum = AccountNum; custTable.Currency = currencyCode; custTable.CustGroup = custGroupId; custTable.TaxGroup = taxGroup; custTable.write(); // Calls insert() or update() ttsCommit; }
Nachteile dieses einfachen Beispiels:
Da aus meiner Sicht die Nachteile überwiegen, würde ich persönlich die obige Variante nur in Ausnahmefällen verwenden. Etwas besser ist die folgende Logik/der folgende Job, der prinzipiell immer noch wie oben arbeitet, d.h. wir schreiben nach wie vor direkt in die Tabelle hinein. Allerdings ist dieser Job bereits um einige Prüfungen erweitert worden, sodaß wir hier eher die Chance haben, daß unsere Entität genauso aussieht, wie wenn diese über das entsprechende (Debitoren-)Formular angelegt worden wäre. static void CreateCustomerSimple_II(Args _args) { custTable custTable; AccountNum accountNum = "8888"; currencyCode currencyCode = "EUR"; custGroupId custGroupId = "DINL"; taxGroup taxGroup = "DINL"; ttsBegin; // Create or update Customer CustTable = CustTable::find(accountNum, true); if( !CustTable) { CustTable.initValue(); } custTable.AccountNum = AccountNum; if( !custTable.validateField(fieldNum(custTable, accountNum))) { throw error("@SYS96731"); } custTable.modifiedField(fieldNum(custTable, accountNum)); custTable.Currency = currencyCode; if( !custTable.validateField(fieldNum(custTable, Currency))) { throw error("@SYS96731"); } custTable.modifiedField(fieldNum(custTable, Currency)); custTable.CustGroup = custGroupId; if( !custTable.validateField(fieldNum(custTable, CustGroup))) { throw error("@SYS96731"); } custTable.modifiedField(fieldNum(custTable, CustGroup)); custTable.TaxGroup = taxGroup; if( !custTable.validateField(fieldNum(custTable, CustGroup))) { throw error("@SYS96731"); } custTable.modifiedField(fieldNum(custTable, TaxGroup)); if(custTable.validateWrite()) { custTable.write(); // Calls insert() or update() } else { throw error("@SYS96731"); } ttsCommit; } Wie gesagt, macht dieser Job prinzipiell genau das selbe wie die ganz oben stehende Variante, nur etwas "eleganter". Allerdings haben wir die Entität, nämlich unseren Debitoren, immer noch nicht vollständig angelegt! Beispielsweise ist im Datenmodell von Dynamics AX 2012 nämlich nicht vorgesehen, daß der Name des Debitoren direkt in der Tabelle CustTable gespeichert wird. Dieser wird im sog. Globalen Adressbuch verspeichert und diesen Umstand berücksichtigt der folgende Job. Auch besitzt dieser nun ein rudimentäres Errorhandling. static void CreateCustomerSimple_III(Args _args) { custTable custTable; DirPartyTable dirPartyTable; AccountNum accountNum = "6666"; Name name = "Debitor 47135"; currencyCode currencyCode = "EUR"; custGroupId custGroupId = "DINL"; taxGroup taxGroup = "DINL"; languageId languageId = "de-AT"; try { ttsBegin; // Create or update Customer CustTable = CustTable::find(accountNum, true); if( !CustTable) { CustTable.initValue(); } custTable.AccountNum = AccountNum; if( !custTable.validateField(fieldNum(custTable, accountNum))) { throw error("@SYS96731"); } custTable.modifiedField(fieldNum(custTable, accountNum)); custTable.Currency = currencyCode; if( !custTable.validateField(fieldNum(custTable, Currency))) { throw error("@SYS96731"); } custTable.modifiedField(fieldNum(custTable, Currency)); custTable.CustGroup = custGroupId; if( !custTable.validateField(fieldNum(custTable, CustGroup))) { throw error("@SYS96731"); } custTable.modifiedField(fieldNum(custTable, CustGroup)); custTable.TaxGroup = taxGroup; if( !custTable.validateField(fieldNum(custTable, CustGroup))) { throw error("@SYS96731"); } custTable.modifiedField(fieldNum(custTable, TaxGroup)); if(custTable.validateWrite()) { custTable.write(); // Calls insert() or update() } else { throw error("@SYS96731"); } // Update party dirPartyTable = DirPartyTable::findRec(custTable.Party, true); dirPartyTable.Name = name; if( !dirPartyTable.validateField(fieldNum(dirPartyTable, Name))) { throw error("@SYS96731"); } dirPartyTable.modifiedField(fieldNum(dirPartyTable, Name)); dirPartyTable.NameAlias = name; if( !dirPartyTable.validateField(fieldNum(dirPartyTable, NameAlias))) { throw error("@SYS96731"); } dirPartyTable.modifiedField(fieldNum(dirPartyTable, NameAlias)); dirPartyTable.LanguageId = languageId; if( !dirPartyTable.validateField(fieldNum(dirPartyTable, LanguageId))) { throw error("@SYS96731"); } dirPartyTable.modifiedField(fieldNum(dirPartyTable, LanguageId)); if(dirPartyTable.validateWrite()) { dirPartyTable.write(); // Calls insert() or update() } else { throw error("@SYS96731"); } ttsCommit; } catch (Exception::Error) { error("@SYS96731"); } } Letztlich haben alle oben angeführten Jobs zumindest einen Nachteil, versucht man nämlich beispielsweise einen 100 Zeichen langen Text in ein Textfeld einzufügen, welches lt. EDT nur 60 Zeichen fassen kann, so wird dieser Text kommentarlos abgeschnitten. |
AX 2012: Erstellen einer DefaultDimension mit mehreren Dimensionen
10.11.2013Microsoft Dynamics AX (Axapta)
Nachstehend ein Code-Beispiel, wie man eine RecId vom Typ DefaultDimension für mehrere Dimensionen generieren kann. Im Beispiel werden die Dimension Kostenstelle mit dem Wert "10", die Dimension Abteilung mit dem Wert "IT" und die Dimension Kategorie mit dem Wert "02" zu einer DefaultDimension kombiniert. Durch den letzten Parameter von findByDimensionAttributeAndValue() wird sichergestellt, daß fehlende Dimensionen angelegt werden (soferne möglich). static void buildDefaultDimension(Args _args) { dimensionAttributeValueSetStorage dimensionAttributeValueSetStorage; dimensionAttribute dimensionAttribute; dimensionAttributeValue dimensionAttributeValue; dimensionDefault dimensionDefault; dimensionAttributeValueSetStorage = new DimensionAttributeValueSetStorage(); // Kostenstelle dimensionAttribute = dimensionAttribute::findByName('Kostenstelle'); if(dimensionAttribute) { dimensionAttributeValue = DimensionAttributeValue::findByDimensionAttributeAndValue(dimensionAttribute, '10', false, true); dimensionAttributeValueSetStorage.addItem(dimensionAttributeValue); } // Abteilung dimensionAttribute = dimensionAttribute::findByName('Abteilung'); if(dimensionAttribute) { dimensionAttributeValue = DimensionAttributeValue::findByDimensionAttributeAndValue(dimensionAttribute, 'IT', false, true); dimensionAttributeValueSetStorage.addItem(dimensionAttributeValue); } // Kategorie dimensionAttribute = dimensionAttribute::findByName('Kategorie'); if(dimensionAttribute) { dimensionAttributeValue = DimensionAttributeValue::findByDimensionAttributeAndValue(dimensionAttribute, '02', false, true); dimensionAttributeValueSetStorage.addItem(dimensionAttributeValue); } dimensionDefault = dimensionAttributeValueSetStorage.save(); info(strFmt("Default dimension recId: %1", dimensionDefault)); } |
AX 2012: Umwandeln/Konvertieren von Werten innerhalb des Data import/export frameworks
07.11.2013Microsoft Dynamics AX (Axapta)
In der Entity einer Processing group kann man über die Schaltfläche Modify source mapping in der nicht grafische Ansicht je Feld Umwandlungen durchführen lassen. Dazu muss man einfach beim jeweiligen Feld über die Schaltfläche Conversion den Dialog Define conversion values öffnen und Quell- sowie Zielwert eintragen. |
AX 2012: DIXF: Gacutil utility for registering .NET 4.0 assembly
02.11.2013Microsoft Dynamics AX (Axapta)
|
AX 2012: Einen Visual Studio Shortcut erstellen
Der finale Eintrag sollte ähnlich dem folgenden aussehen: Startet man Visual Studio nun über diese Verknüpfung, kann man im Application Explorer ganz oben Layer und ggf. Model überprüfen.
|
|
|
|
|
|
|
Benötigt man für eine Tabelle eine sog. AX<Table>-Klasse kann man sich diese mit Hilfe der Klasse AxGenerateAxBCClass generieren lassen.
Dazu einfach diese Klasse im AOT per rechter Maustaste aufrufen und dem Assistenten folgen.
Die auf diese Art & Weise generierte Klasse muss unter manchen Umständen noch etwas bearbeitet werden, dennoch geht der Vorgang rascher von der Hand, als die Klasse komplett selbst erstellen zu müssen.
Und wenn sich die Tabelle ändert, beispielweise wenn neue Felder hinzukommen, kann man die AxGenerateAxBCClass einfach nochmals aufrufen und die AX<Table>-Klasse wird entsprechend erweitert.
Wie man solche AX<Table>-Klassen verwendet, habe ich u.a. hier beschrieben.