Dynamics AX Blog - Dynamics AX 2012 - Beiträge vom März 2014

RSS-Feed dieser Version
AX 2012: Ausführen einer statischen Klassen-Methode in der CIL
15.03.2014Microsoft Dynamics AX (Axapta)
Mit Hilfe der nachstehenden Klasse möchte ich zeigen, wie man in Dynamic AX 2012 X++ Code als CIL ausführt. Die Klasse MyDemoClass enthält eine statische Methode countSalesRecords() welche die eigentliche Logik enthält.
Zu beachten sind vor allem die Modifier der jeweiligen Methoden sowie das Parameter-Profil der Methode countSalesRecordsIL() (ein- und ausgehender Container). Hätte die Methode keinen eingehenden Container als Parameter, würde AX behaupten, die Methode nicht zu kennen:
Nachdem man die Klasse erstellt und die CIL inkrementell kompiliert hat, kann man die Klasse per rechter Maustaste ausführen. Dadurch wird die main()-Methode aufgerufen welche die Logik der Methode countSalesRecords() auf die altbewährte Art & Weise aufruft und zusätzlich in der CLR ausführt. Vorausgesetzt natürlich der Benutzer hat in seinen Benutzer-Optionen die Option Geschäftliche Arbeitsgänge in CIL ausführen aktiviert! class MyDemoClass { }
public server static counter countSalesRecords(SalesStatus _salesStatus) { Query query; QueryBuildDataSource qbds_salesTable; QueryBuildDataSource qbds_salesLine; QueryRun queryRun; Counter r; setPrefix(strFmt("isCLRSession: %1", enum2str(xSession::isCLRSession()))); setPrefix(enum2str(_salesStatus)); query = new query(); qbds_salesTable = query.addDataSource(tableNum(salesTable)); qbds_salesTable.addSelectionField(fieldNum(salesTable, RecId)); qbds_salesLine = qbds_salesTable.addDataSource(tableNum(salesLine)); qbds_salesLine.addSelectionField(fieldNum(salesLine, RecId)); qbds_salesLine.joinMode(JoinMode::InnerJoin); qbds_salesLine.relations(true); SysQuery::findOrCreateRange(qbds_salesTable, fieldNum(SalesTable, SalesStatus)).value(queryValue(_salesStatus)); queryRun = new queryRun(query); while(queryRun.next()) { r++; } info(strFmt("Records: %1", r)); return r; }
private server static container countSalesRecordsIL(container _con) { SalesStatus salesStatus; Counter c; container cReturn; salesStatus = conPeek(_con, 1); // Call method and get it's return value c = MyDemoClass::countSalesRecords(salesStatus); return conPoke(cReturn, 1, c); }
public server static counter countSalesRecordsWrapper(SalesStatus _salesStatus) // Same parameter-profile as method, which is called in CIL { container resultContainer; Counter c; new XppILExecutePermission().assert(); resultContainer = Global::runClassMethodIL(classStr(MyDemoClass), staticMethodStr(MyDemoClass, countSalesRecordsIL), [_salesStatus]); CodeAccessPermission::revertAssert(); // Get return value through resultContainer c = conPeek(resultContainer, 1); return c; }
public static server void main(Args _args) { setPrefix("MyDemoClass"); MyDemoClass::countSalesRecords(SalesStatus::Invoiced); MyDemoClass::countSalesRecordsWrapper(SalesStatus::Backorder); } |
Werte eines Base-Enums durchlaufenSysDictEnum SysDictEnum = new SysDictEnum(enumNum(SalesStatus)); int i; for (i=0;i<SysDictEnum.values();i++) { info(SysDictEnum.index2Label(i)); } |
SQL-Fehler beim Öffnen/Synchronisieren einer TabelleTritt beim Öffnen oder Synchronisieren einer - meist neu erstellten - Tabelle der folgende Fehler auf
so kann die Ursache sein, daß die Tabelle ein Feld enthält, dessen Name ein "Reserved Word" der SQL-Datenbank ist. Beispielsweise darf ein Feld nicht Primary genannt werden. |
Zugriff auf externe Datenbank via ODBCIm folgenden ein paar Code-Beispiele wie man aus Dynamics AX heraus auf externe Datenbanken lesend und schreibend zugreifen kann. Die Beispiele basieren auf folgendem MSDN-Beitrag: Lesender Zugriff (SELECT)// X++, Main method in a class. static public void Main(Args _args) { LoginProperty loginProperty; OdbcConnection odbcConnection; Statement statement; ResultSet resultSet; str sql, criteria; SqlStatementExecutePermission perm; ; // Set the information on the ODBC. loginProperty = new LoginProperty(); loginProperty.setDSN("ExternalDB_32bit"); loginProperty.setDatabase("ExternalDatabaseName"); //Create a connection to external database. odbcConnection = new OdbcConnection(loginProperty); if (odbcConnection) { sql = "SELECT * FROM items;"; //Assert permission for executing the sql string. perm = new SqlStatementExecutePermission(sql); perm.assert(); //Prepare the sql statement. statement = odbcConnection.createStatement(); resultSet = statement.executeQuery(sql); //Cause the sql statement to run, //then loop through each row in the result. while (resultSet.next()) { //It is not possible to get field 3 and then 1. //Always get fields in numerical order, such as 1 then 2 the 3 etc. print strFmt("%1 - %2", strRTrim(resultSet.getString(1)), strRTrim(resultSet.getString(2))); } //Close the connection. resultSet.close(); statement.close(); } else { error("Failed to log on to the database through ODBC."); } } |
|
|
|
|
|
|
Nachstehend ein kurzer Job, mit dessen Hilfe man AOT-Elemente zu einem bestehenden Shared Project hinzufügen kann.
{
projectNode projectNode;
TreeNode treeNode;
#AOT
#AOTExport
projectNode = infolog.projectRootNode();
projectNode = projectNode.AOTfindChild(#expProjectShared);
projectNode = projectNode.AOTfindChild('MyProject');
// Add objects
treenode = TreeNode::findNode(#TablesPath+'\\'+tableid2name(tablenum(CustGroup)));
projectNode.addNode(treenode);
treenode = TreeNode::findNode(#TablesPath+'\\'+tableid2name(tablenum(VendGroup)));
projectNode.addNode(treenode);
treenode = TreeNode::findNode(#ClassesPath+'\\'+classStr(PriceDisc));
projectNode.addNode(treenode);
}
Das geänderte Projekt sieht beispielsweise wie folgt aus: