Erstellen einer Entität - beispielsweise eines Debitoren - per Code
12.11.2013Microsoft Dynamics AX (Axapta)
|
Dieser Beitrag bezieht sich auf die Version:
Dynamics AX 2012
Dynamics AX 2012
|
|
|
|
|
|
Dieser Beitrag bezieht sich auf die Version:
Dynamics AX 2012
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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.
Und diese aus meiner Sicht einfachste Variante ist, mittels X++ Logik einzubinden, welche die Daten direkt in die Tabelle schreibt. Ein solches Stück Code kann wie folgt aussehen:
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:
Es wird keine Logik aufgerufen, die bestimmte Felder eines neuen Datensatz initalisiert (CustTable.initValue())
Weder jene die im AOT als Mandatory gekennzeichnet sind (beispielsweise CustTable.CustGroup), noch solche die über die Programmlogik nur unter bestimmten Umständen ausgefüllt werden müssen (beispielsweise CustTable.TaxGroup).
Man kann in die Felder - solange es der Datentyp zulässt - irgendwelche Werte reinschreiben, beispielsweise auch Debitorengruppen, die im AX gar nicht vorhanden sind.
Beispielsweise werden normalerweise, wenn man eine Debitorengruppe einträgt, Standardwerte diese Gruppe in den Debitoren übernommen (Feld PaymTermId über die Methode initFromCustGroup())
Vorteile dieser Variante:
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.
Es werden die Methoden initValue(), validateField(), modifiedField() und validateWrite() explizit aufgerufen. Diese wiederrum führen jeweils weitere Logik aus.
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.