Dynamics AX Blog - Beiträge vom März 2014
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 durchlaufen
SysDictEnum 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: