...feel the spirit of Microsoft Dynamics AX RSS 2.0
 Monday, April 02, 2007

Ab der Version 4.0 von Dynamics AX ist es möglich, an einem AOS, die Neuanmeldung von Benutzern zu sperren.

Um Benutzern die Anmeldung an einem AOS zu untersagen muss der entsprechende AOS auf dem Reiter „Serverinstanzen“ der Maske „Onlinebenutzer“ angewählt werden und der Button „Neue Clients ablehnen“ betätigt werden.
Hierbei wird der AOS in den Status „Belastung“ geschaltet.
Ab diesem Zeitpunkt akzeptiert dieser AOS keine Neuanmeldungen mehr.

 

Mit dem Button „Neue Clients akzeptieren“ kann dies Rückgängig gemacht werden.

Der AOS wird in den Status „Aktiv“ gesetzt.

 

Allerdings bringt das Untersagen von Neuanmeldungen in einer Dynamics AX Umgebung mit nur einem AOS auch einige Gefahren mit sich.

 

Wird der Client bzw. die Benutzersitzung des Benutzers mit administrativer Berechtigung geschlossen, und hat dieser keine weiteren aktiven Sitzungen mit ebenfalls administrativen Berechtigungen geöffnet, so hat sich der Administrator selbst vom System ausgesperrt.
Die Sperrung von Neuanmeldungen kann nun nicht mehr rückgängig gemacht werden.

 

Es ist dann nur noch möglich, den AOS neu zu starten um sich wieder anmelden zu können, da bei einem Neustart eines AOS dessen Status automatisch wieder auf „Aktiv“ gesetzt wird.

 

 

Monday, April 02, 2007 12:39:57 PM (Mitteleuropäische Zeit, UTC+01:00)  Axel Kühn  #    Comments [0] - Trackback
 | 

 Friday, March 30, 2007

Das man in Microsoft Dynamics Ax mittels Drag&Drop einfach Tabellenfelder (Fields) oder Tabellenfeldgruppen (Fieldgroups) in Masken (Forms) einfügen kann ist allgemein bekannt.
Mittels Tabellenfeldgruppen können die gewünschten Felder in die Masken integriert werden. Dadurch ist das Hinzufügen oder Entfernen der Tabellenfelder auf einfache Art Zentral auf Tabellenebene möglich, ohne die Maske anpassen zu müssen.

Was für mich bis dato noch neu war: Es ist auch möglich auf einem Grid eine Tabellenfeldgruppe zu hinterlegen und direkt diesem FormControl alle Felder, die der Tabellenfeldgruppe hinterlegt wurden, zuzuweisen. Microsoft hat in der aktuellen Version von Microsoft Dynamics Ax 4.0 damit auch schon angefangen, dieses in den Forms aktiv zu nutzen. Bisher ist mir das zumindest noch nicht aufgefallen. In den Masken zur Adressverwaltung ("Address...") werden hier nun auf dem Reiter "Überblick" die Felder mittels Feldgruppe auf dem Grid hinzugefügt (bsp: Form "AddressCountryRegion") oder es wird die Tabellenfeldgruppe direkt dem Grid zugeordnet (bsp: Form "AddressZipCodes").

Die Zuordnung erfolgt immer über die Eigenschaft "DataGroup". Die Eigenschaft "DataSource" muss selbstverständlich auch hierzu vorher gefüllt werden um dann mittels Lookup in der Eigenschaft "DataGroup" eine Auswahl auf alle Tabellenfeldgruppen der aktuell ausgewählten Tabelle zu erhalten. 


Eigenschaft der FormGridControl "Grid"


Nach Auswahl der DataGroup werden alle Felder automatisch dem aktuellen Objekt zugeordnet.


FormGridControl erhält nach Zuweisung der Eigenschaft "DataGroup" alle Felder der ausgewählten Feldgruppe


Man muss aber beachten, das ein manuelles hinzufügen von Feldern nicht mehr funktioniert. D.h. im FormDesigner sieht alles prima aus, alle Felder, auch die manuell hinzugefügten, werden angezeigt, beim Aufruf der Maske sind aber nur die Felder sichtbar, die auch in der aktuellen Tabellenfeldgruppe hinterlegt wurden.
Wird jedoch die Eigenschaft AutoDataGroup auf "Yes" gesetzt ist ein manuelles hinzufügen von Elementen nicht mehr möglich! Auch bereits vorhandene Elemente werde, sofern manuell hinzugefügt und nicht in der aktuellen Feldgruppe hinterlegt, wieder entfernt. Wird eine Feldgruppe mittels Drag&Drop in der Form hinzugefügt, ist die Eigenschaft AutoDataGroup schon standardmäßig auf "Yes" gesetzt.
Es gilt aber immer: Sobald die DataGroup befüllt ist, werden alle Elemente die nicht der aktuellen Feldgruppe auf der Tabelle zugeordnet wurde nicht mehr angezeigt/ berücksichtigt.

Meiner Meinung wieder ein Schritt in die richtige Richtung, denn dadurch lassen sich Anpassungen an einer Form weiter minimieren. Das kann wieder einen verminderten Anpassungsaufwand, speziell bei Upgrades bedeuten, da bei Masken meiner Erfahrung nach mit die größte Zeit aufgewendet werden muss.
Friday, March 30, 2007 10:08:52 PM (Mitteleuropäische Zeit, UTC+01:00)  Mathias Füßler  #    Comments [0] - Trackback
 | 

 Tuesday, March 27, 2007

Wie schon in diesem Artikel beschrieben ist es auch unter Dynamics AX 4.0 möglich, den Text der Titelleiste zu verändern.

Hierzu ein kurzes Beispiel:

void workspaceWindowCreated(int _hWnd)
{
// Put workspace window specific initialization here.
str orgTitleBarText, newTitleBarText;
int posBracket, lenTitle;
;
//Show the configuration file name in the titlebar - START


//Without session id:
orgTitleBarText = WinAPI::getWindowText(_hWnd);
lenTitle = strLen(orgTitleBarText);
posBracket = strScan(orgTitleBarText, "[", 1, lenTitle);

newTitleBarText = subStr(orgTitleBarText, 1, posBracket);
newTitleBarText = strfmt("%1%2]", newTitleBarText, xInfo::configuration());

WinAPI::setWindowText(_hWnd, newTitleBarText);

//Show the configuration file name in the titlebar - END
}

Die Anpassung der Methode "workspaceWindowCreated" der Klasse "Info" liefert folgenden Text in der Titelleiste:

Hierbei wird der Name der Dynamics AX Client Configuration, die für diese Session verwendet, wird innerhalb der eckigen Klammern angezeigt.

Tuesday, March 27, 2007 8:22:24 AM (Mitteleuropäische Zeit, UTC+01:00)  Axel Kühn  #    Comments [6] - Trackback
 | 

 Monday, March 26, 2007

Es gibt Tage da wundert man sich über Dinge mit denen man alltäglich zu tun hat...
So geschehen mit QueryRanges und deren QueryValues...

Beim Definieren einer QueryRange ist darauf zu achten, dass die QueryValue als Datentyp der QueryRange festgelegt wird. Wird beim Filtern auf einem Preis (Real) ein String als Kriterium festgelegt erhält man je nachdem ob dieser String in einen gültigen Realwert gewandelt werden konnte unterschiedliche Resultate. Möglicherweise werden, wenn ein ungültiges Kriterium festgelegt wurde, alle Datensätze zurückgegeben.



Monday, March 26, 2007 7:13:25 PM (Mitteleuropäische Zeit, UTC+01:00)  Mathias Füßler  #    Comments [0] - Trackback
 | 

Unter Microsoft Dynamics AX 3.0 war es recht einfach den Text in der Titelleiste zu verändern. Dies war sogar auf mehere verschiedene Arten möglich.
Unter Dynamics AX 4.0 funktionieren diese bekannten Methoden leider nicht mehr.

Allerdings existiert unter Dyanamics AX 4.0 eine neue Möglichkeit den Text in der Titelleiste zu verändert.
Hierfür ist es nur erforderlich die Methode "workspaceWindowCreated" der Klasse "Info" zu überschreiben.

Wie dies genau gemacht werden kann, ist in dem Artikel Configuration in title bar auf Axaptapedia beschrieben.

Monday, March 26, 2007 7:13:22 PM (Mitteleuropäische Zeit, UTC+01:00)  Axel Kühn  #    Comments [0] - Trackback
 | 

 Friday, March 23, 2007

Der Umgang mit Queries ist auch in Microsoft Dynamics AX sehr einfach, sofern man mit den Objekten vertraut ist.
Angefangen mit einem einfachen Query, der kann entweder auf Basis eines im AOT (Query) definierten Querys erzeugt werden
oder auch komplett neu mit x++ erzeugt werden kann.

Folgende Okjekte werden verwendet

Query (Abfrage)
QueryRun (führt die Abfrage aus)
QueryBuildDataSource (DataSource in der Abfrage)
QueryBuildRange (Range (Einschränkung) auf der DataSource)


Kurzes Beispiel:

Das Ergebniss ist die Ausgabe alle Artikel bei denen die Artikelgruppe "Teile" hinterlegt wurde.

Auf Basis eines im AOT definierten Queries

//Ein neues Query Objekt, verwendet wird die Query (Im AOT) "InventTable"
Query queryInventTable = new Query(querystr(InventTable));

QueryRun queryRun;
QueryBuildDataSource queryDS;
QueryBuildRange queryRange;
InventTable inventTable;
;
// Datasource zuordnen
queryDS = queryInventTable.dataSourceTable(tablenum(InventTable));

// Prüfen ob Range schon vorhanden
if (queryDS.findRange(fieldnum(InventTable, ItemGroupID)))
queryRange = queryDS.findRange(fieldnum(InventTable, ItemGroupID));
else
queryRange = queryDS.addRange(fieldnum(InventTable, ItemGroupID));

queryRange.value("Teile");

// queryRun mit dem aktuell neu erstellen query auf Basis des Queries "InventTable" erzeugen
queryRun = new QueryRun(queryInventTable);

// alle Datensätze ausgeben
while (queryRun.next())
{
inventTable = queryRun.get(tablenum(InventTable));
print InventTable.ItemID;
}
pause;


Komplett in X++ definierte Query

//Ein neues leeres Query Objekt
Query query = new Query();
QueryRun queryRun;
QueryBuildDataSource queryDS;
QueryBuildRange queryRange;

InventTable inventTable;
;
// Datasource (Tabelle InventTable) hinzufügen
queryDS = query.addDataSource(tablenum(InventTable));

// Range definineren
queryRange = queryDS.addRange(fieldnum(InventTable, ItemGroupID));
queryRange.value("Teile");

// alternative
// Range definineren
query.dataSourceTable(tablenum(InventTable)).addRange(fieldnum(InventTable, ItemGroupID)).value("Teile");

// queryRun mit dem aktuell neu erstellen query erzeugen
queryRun = new QueryRun(query);

// alle Datensätze ausgeben
while (queryRun.next())
{
inventTable = queryRun.get(tablenum(InventTable));
print InventTable.ItemID;
}

Bei diesem einfachen Query macht es keinen Unterschied ob im AOT definiertes Query verwendet wird, oder ob man die definition komplett in X++ vornimmt.
Benutzt man ein Query das schon irgendwo definiert wurde und möchte dieses verwenden, sollte man immer auf schon vorhandene Objekte (siehe findRange)
zurückgegriffen werden sofern schon vorhanden.Ansonsten fügt man immer wieder dasselbe Objekt hinzu, bei Ranges hat das dann zufolge, das in der Abfrage nicht mehr auf die aktuell
definierte Range zurückgegriffen wird, sondern auf alle davor definieren Ranges ebenfalls.
Das kann sehr gut in dem unterem Beispiel getestet werden, indem man einfach eine neue Range auf demselben Feld wie schon zuvor definiert hinzufügt und eine anderen
Wert festlegt.

Das Ergebnis ist die Ausgabe alle Artikel bei denen die Artikelgruppe "Teile" und "Lampen" hinterlegt wurde.

// Range definineren
queryRange = queryDS.addRange(fieldnum(InventTable, ItemGroupID));
queryRange.value("Teile");

// Neue Range auf demselben Feld. ein andere Wert wird festgelegt
queryRange = queryDS.addRange(fieldnum(InventTable, ItemGroupID));
queryRange.value("Lampen");


Der Zugriff auf einzelne Elemente (wie DataSource oder Range) der Query ist jeweils immer gleich. Bei der DataSource sollte immer beachtet werden, dass es ggf. mehrere Objekte vom selben Typ (Tabelle) geben könnte. Ein gutes Beispiel hierfür sind wieder die Artikel (InventTable) mit den drei verknüpften Lagermodulparameter (InventTableModule). Wir hierbei der Zugriff auf die DataSource über tablenum gesteuert erhält man immer ein und dieselbe DataSource und nicht wie evtl gewünscht alle drei DataSources.
Der Zugriff sollte dann über den DataSource-Namen erfolgen, der immer eindeutig ist, sogar dann wenn das hinzufügen per x++ geschieht.

Hinzufügen von drei neuen DataSources und der Zugriff auf jeder DataSource der aktuellen Abfragen, inkl. Ausgabe des Namen

Query query = new Query();
counter dsCount;
;
// Datasource (Tabelle InventTable) hinzufügen
queryDSInvent= query.addDataSource(tablenum(InventTable));

//neue relation auf Lagermodulparameter (3mal)
queryDSInvent.addDataSource(tablenum(InventTableModule)).relations(true);
queryDSInvent.addDataSource(tablenum(InventTableModule)).relations(true);
queryDSInvent.addDataSource(tablenum(InventTableModule)).relations(true);

/ Ausgabe aller DataSources die im aktuellen Query vorhanden sind
for (dsCount = 1; dsCount <= query.dataSourceCount(); dsCount++)
{
print query.dataSourceNo(dsCount).name();
}
pause;

Wird der DataSource kein Name zugewiesen erzeugt Dynamics AX automatisch einen eindeutigen Namen (Tabellenname_Zähler).

Hinterlegt man nun noch bei den LagerModulparametern eine Range (Verkauf, Einkauf, Lager) auf den Lagertyp hat man im groben die Standardquery (es fehlt noch die Lagerortverwaltung Tabelle) der Artikelmaske nachgebaut.

// Lager
queryDS = queryDSInvent.addDataSource(tablenum(InventTableModule));
queryDS.relations(true);
queryDS.joinMode(JoinMode::InnerJoin);
queryRange = queryDs.addRange(fieldnum(InventTableModule,ModuleType));
queryRange.value(queryValue(ModuleInventPurchSales::Invent));

Prinzipiell kann man mit dieser Query auch die Query auf der Maske InventTable überladen. Diee Anzeige der Artikel klappt weiterhin wunderbar
nur die Referenzen auf die zusätzlichen FormDataSources geht hierbei verloren. Dadurch funktioniert die Anzeige und Bearbeitung der Daten aus diesen FormDataSources dann nicht mehr.

Spasseshalber aber noch der Quellcode, der auch die Query der Form überlädt.

Job_QueryEinfachFormRun.xpo (3,05 KB)
Friday, March 23, 2007 10:42:02 PM (Mitteleuropäische Zeit, UTC+01:00)  Mathias Füßler  #    Comments [0] - Trackback
 | 

 Friday, March 16, 2007

Viele Wege führen nach Rom, so auch in Microsoft Dynamics AX beim Anpassen der Masken (Forms).


Eine Form direkt anzupassen kann auf den ersten Blick immer ein einfachere Weg sein, nur sollte man bedenken das es hier bei einem Update mit die meißten Schwierigkeiten bzw. die meißte Arbeit geben kann. Dabei kann man fast jede Anpassung an der Maske auch über X++ steuern.

Hier ein paar einfache Beispiele dafür:

Manipulation der Datasource.

FormRun        fr;
Args           args = new Args();
FormDataSource fds;
;
// Form Name InventTable
args.name(formstr(InventTable));
fr = new FormRun(args);
// init der Form
fr.init();
// Datasource der Form
fds = fr.dataSource(1);
// Neue Range auf der Datasource erzeugen
fds.query().dataSourceTable(tablenuM(InventTable)).addRange(fieldnum(InventTable, itemID)).value(“Wert”);
fr.run();
fr.wait();

In dem o.g. Beispiel wird eine neue Range auf der Datasource „InventTable“ erzeugt, ohne einen direkten Eingriff auf der Form zu machen.

Weitere Möglichkeiten der Datasource Manipulation

// Datasource darf nicht editierbar sein
fds = fr.dataSource(1);
fds.allowEdit(False);

Prinzipiell kann über X++ alles manipuliert werden, was auch direkt in der Form manipuliert werden kann.

Der Zugriff auf einzelne Felder der Datasource erfolgt über die Methode object(), es muss nur noch die Kennung des Objektes übergeben (Feldnummer) um Zugriff zu erhalten.

// Artikelnummer ausblenden
fds = fr.dataSource(1);
fds.object(fieldnum(InventTable, ItemID)).visible(false);


Man erhält den vollen Zugriff auf die Eigenschaften und kann nach belieben die Objekte verändern. Das einzige was zusätzlich noch gemacht werden muss, ist den Aufruf der Maske zu verändern. So kann ein neues MenuItem erstellt werden, welches das Ursprüngliche MenuItem ersetzt oder es wird einfach das MenuItem verändert. So wird anstelle der Maske eine Klasse aufgerufen, die die Manipulation an der Maske vornimmt. Performanceeinbußen habe ich noch nicht oder nur im geringen Maße feststellen können.

Die einzigen wirklichen Probleme die ich bei solchen Formanpassungen hatte, war das Einfügen einer neuen Formdatasource. Man kann die FormDatasource zur Laufzeit in die Form einfügen, leider muss die Form aber geschlossen und wieder neu aufgerufen werden um Zugriff auf die Formdatasource zu erhalten und um diese dann im Design der Form nutzen zu können. Bei manchen Forms kam es beim Neuaufruf der Form zu sehr seltsamen Verhalten, wie zum Beispiel,  das Formcontrols die automatisch Deklariert wurden (Autodeclaration = Yes) ihre Wertigkeit verlieren. So wurde bespielsweise aus einer FormStringControl eine FormDataSource. Hier ist also bei der Anwendung Vorsicht geboten.

Anbei noch ein Job der die Kreditorenmaske manipuliert. Es wird hier eine neue Datasource (Bestellungen) angefügt und in einem neuen Grid angezeigt. Seltsamerweiße klappt dieses Vorgehen mit der Kreditormaske sehr gut, bei den Debitoren bekam ich nur o.g. Fehlermeldungen bei Aufruf.
 

Der ursprünglich Link scheint nicht zu funktionieren. Hier nochmal ein neuer Versuch

Job_MaskeKreditorBestellung.xpo (2,52 KB)

Und wenn das auch nicht funktionieren sollte, nochmal als Text...

// Changed on 15 Mär 2007 at 21:14:18 by jinx (starside.eu)
// Manipulation des Aufrufes der Maske Kreditoren
static void MaskeKreditorBestellung(Args _args)
{
FormRun fr;
Args args = new Args();
FormRun neuformRun;
FormBuildDataSource formBuildDataSource;
FormGridControl fgc;
FormGroupControl fGroupCtrl;
;
// Form Name VendTable -> Kreditoren
args.name(formstr(VendTable));
fr = new FormRun(args);

// Neue DataSource einfügen
formBuildDataSource = fr.form().addDataSource("PurchTable");
// Tabelle der Datasource zuordnen
formBuildDataSource.table(tablenum(PurchTable));
// Datasource mit der Tabelle "VendTable" verknüpfen
// Wichtig: Unbedingt den Namen der Datasource übergeben!
formBuildDataSource.joinSource(fr.form().dataSource(1).name());
// Art der Verknüpfung festlegen
formBuildDataSource.linkType(1);

formBuildDataSource.allowCreate(false);
formBuildDataSource.allowDelete(false);
formBuildDataSource.allowEdit(false);

// Neue Gruppe Erzeugen
fGroupCtrl = fr.form().design().addControl(FormControlType::Group,"PurchOderGroup");
// Die Neue Datasource der neuen Gruppe zuordnen
fGroupCtrl.dataSource(formBuildDataSource.id());
// Neues Grid erzeugen
fgc = fGroupCtrl.addControl(FormControlType::Grid,"PurchOderGrid");
// Die Neue Datasource dem neuen Grid zuordnen
fgc.dataSource(formBuildDataSource.id());
// Feld "Bestellnummer" ins Grid einfügen
fgc.addDataField(formBuildDataSource.id(), fieldnum(PurchTable, PurchID));
// Feld "Kreditorennummer" ins Grid einfügen
fgc.addDataField(formBuildDataSource.id(), fieldnum(PurchTable, OrderAccount));

// Die Form in der wir gerade die Datasource eingefügt haben, den Args übergeben
args.object(fr.form());

// Neue FormRun aufgrund der Manipulierten Form erzeugen und aufrufen
neuformRun = classFactory.formRunClass(args);
neuformRun.init();
neuformRun.run();
neuformRun.wait();
}


Friday, March 16, 2007 7:19:27 PM (Mitteleuropäische Zeit, UTC+01:00)  Mathias Füßler  #    Comments [0] - Trackback
 | 

 Tuesday, February 27, 2007

Kaum ist Version 4 (4.01) von Microsoft Dynamics AX erschienen, tauchen auch schon die ersten Informationen über die weitere Zukunft von Microsoft Dynamics AX auf.

Wie in diesem Bericht (http://www.directionsonmicrosoft.com/sample/DOMIS/update/2006/08aug/0806dwtpcp.htm) zu lesen ist, soll die nächste Version von Microsoft Dynamics AX ein UI ähnlich dem von Microsoft Office 2007 bekommen.
Weiterhin soll es noch eine tiefere Integration in bestehende Microsoft Technologien geben. Ein Beispiel wäre hier die geplante Verlagerung der Entwicklungsumgebung ins Visual Studio.

Genauere Informationen können dem oben genannten Bericht entnommen werden.

Ein erster Screenshot (Prototype) des nächsten Microsoft Dynamics AX ist hier zu finden:
http://www.directionsonmicrosoft.com/sample/DOMIS/update/2006/08aug/0806dwtpcp_illo.htm

Tuesday, February 27, 2007 7:10:50 PM (Mitteleuropäische Zeit, UTC+01:00)  Axel Kühn  #    Comments [0] - Trackback
 | 

 Monday, February 19, 2007

Auch in Microsoft Dynamics AX kann man mittels ADO (ActiveX Data Objects) auf praktisch jede Art von Datenbanken zugriffen. Die Benutzung ist denkbar einfach und wird durch folgende Objekte gehandhabt.

  • CCADOConnection (Datenbankverbindung)
  • CCADORecordSet (Datensatzsammlung)
  • CCADOFields (Feldsammlung)
  • CCADOField (Datenfeld)

Wurde schon eine ODBC Verbindung konfiguriert ist die Verwendung der CCADOConnection denkbareinfach und könnte für eine ODBC Verbindung mit dem Name "altDatenKunden" die Beispielsweise auf eine mySQL Datenbank verweist wie folgt aussehen.

CCADOConnection adoConnection = new CCADOConnection();
adoConnection.open("DNS=altDatenKunden");

Die Parameter werden hier immer als string übergeben und können sich Unterscheiden je nachdem auf welche Datenbank zugegriffen werden soll.

Um CCADORecordSet zu inizialisieren muss vorher erst noch eine SQL Anweisung definiert werden. Die SQL Anweisung wird als String zusätzlich zur CCADOConnection dem Konstruktor übergeben.

str SQLstring = "SELECT * From Artikeltabelle";
CCADORecordSet adoRecordSet = new CCADORecordSet();

adoRecordSet.open(SQLstring, adoConnection);

Über adoRecordSet enthält man nun Zugriff auf alle Datensätze aus der Tabelle "Artikeltabelle". Mittels einer Schleifen kann man nun auf jeden einzelen Datensatz zugreifen.

while (!adoRecordSet.EOF())
{
adoRecordSet.moveNext();
}

Um nun Zugriff auf die Daten zu erhalten brauchen wir noch CCADOFields, bzw. CCADOField

CCADOFields adoFields;
CCADOField adoField;

adoFields = adoRecordSet.fields();
adoField = adoFields.itemName("Artikelnummer");

print adoField.value();

Durch diese Anweisungen wird nun das Feld "Artikelnummer" des aktuellen Datensatzes ausgegeben.

Direkte Zuweisungen zum Datenfeld:

  • Über den Feldnamen  

    adoField = adoFields.itemName("Artikelnummer");

                       
  • Über die Feldnummer 

    adoField = adoFields.itemIDx(1);

Über die Methode

adoFields.count()

erhält man die gesamte Anzahl der Felder, der aktuellen Tabelle und erhält so Zugriff auf jedes einzelne Tabellenfeld auch ohne deren Benennung und/ oder Anzahl zu kennen..

for( i =1 ; i<= adoFields.count() ; i++)
{
adoField = adoFields.itemIdx(i);
print adoField.value();
}

Die Methode value() der Klasse CCADOField gibt den Wert des Feldes immer als den richtigen Axapta Basis Wertetyp (str, int, real usw.) zurück. Somit muss man sich über eine Typenwandlung in der Regel keine Gedanken machen.

Zum Abschluss noch ein komplettes Bespiel.

CCADOConnection Connection;
str SQL;
CCADORecordSet adoRecordSet;
;
// Neue ADO Connection
Connection = new CCADOConnection();

// Verdingung zur Datenbank öffnen
Connection.open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\altDatenKunde.mdb");

// Neuer RecordSet
adoRecordSet = new CCADORecordSet();

// SQL Anweisung
sql = strfmt("SELECT * FROM %1","Artikeltabelle");

// Datensatzsammlung mit Verbindung zur Datenbank und anhand der SQL Anweisung
adoRecordSet.open(sql, connection);

// Alle Datensätze
while (!adoRecordSet.EOF())
{
// Ausgabe des Erstfeldes
print adoRecordSet.fields().itemIdx(1).value();
// Ausgabe des Feldes "Artikelbestand"
print adoRecordSEt.fields().itemName("Artikelbestand").value();

// Nächster Datensatz
adoRecordSet.moveNext();
}

adoRecordSet.close(); //Recordset schließen
Connection.close(); //Connection schlißen

pause;


 

Monday, February 19, 2007 7:05:42 PM (Mitteleuropäische Zeit, UTC+01:00)  Mathias Füßler  #    Comments [0] - Trackback


 Monday, January 29, 2007

Möchte man nach einem Upgrade von Microsoft Dynamics AX 4.0 auf Microsoft Dynamics AX 4.01 einen neuen Benutzer anlegen erhält man die Fehlermeldung "".

Dies läßt erst einmal auf ein Problem im Quellcode von Microsoft Dynamics AX schließen.

Grund für die Fehlermeldung ist aber kein Fehler im Quellcode, sondern ein fehlerhafter Datensatz in der Tabelle "SysPerimeterNetworkParms". In diesem Datensatz steht im Feld "PNType" ein ungültiger Wert.

Wird dieser Wert auf einen gültigen Wert (None) geändert, können auch wieder neue Benutzer im System angelegt werden.

Folgender Job kann zur Behebung des Problems verwendet werden:
(Verwendung auf eigene Gefahr. Es wird keine Garantie oder Haftung für die Funktion und Richtigkeit des Quellcodes gegeben. )

static void CorrectAxaptaUserImportError(Args _args)
{
SysPerimeterNetworkParams p;
DataArea a;
;
while select a
{
changecompany(a.Id)
{
p = null;
ttsbegin;
while select forupdate p
{
p.PNType = PerimeterNetworkType::None;
p.update();
}
ttscommit;
}
}
}

Monday, January 29, 2007 4:32:58 PM (Mitteleuropäische Zeit, UTC+01:00)  Axel Kühn  #    Comments [0] - Trackback
 |  | 

 Thursday, January 25, 2007

Im Microsoft PartnerSource ist ein Dokument erhältlich, welchen den Updateprozess beschreibt, der durchzuführen ist, wenn man ein Update von Microsoft Dynamics AX 4.0 auf Microsoft Dynamics AX 4.01 durchführen möchte.

Alles in allem ist dieses Dokument eine sehr gute Informationsquelle, die fast alle Einzelheiten, die bei dem Update zu beachten sind, erläutert.

Bedauerlich ist nur, dass eine sehr wichtige "Kleinigkeit" nicht in diesem Dokument erwähnt wird. Hält man sich strickt an die Dokumentation, so wird man leider feststellen, dass sich der AOS nach der Installation von Microsoft Dynamics AX 4.01 nicht mehr starten lässt. Es wird zwar ein Eintrag im EventLog erzeugt, dieser ist aber nicht besondern hilfreich (Error 110).

Grund für diese Fehlermeldung sind die beiden StoredProzedures die ab Microsoft Dynamics AX Version 4.0 in jeder Microsoft Dynamics AX Datenbank vorhanden sein müssen. Da die Datenbank an sich nicht "geupdatet" wird, werden diese SP`s ebenfalls nicht geändert und bleiben damit auf dem Stand von Microsoft Dynamics AX 4.0. Und leider scheint Microsoft Dynamics AX 4.01 genau mit diesen SP`s nicht zusammen arbeiten zu können.

Die Lösung des Problems gestaltet sich zum Glück recht einfach:

Die SP's müssen einfach nur gegen die beiden SP's einer Microsoft Dynamics AX 4.01 Datenbank ausgetauscht werden und schon funktioniert der AOS wie erwartet.

Thursday, January 25, 2007 11:21:32 PM (Mitteleuropäische Zeit, UTC+01:00)  Axel Kühn  #    Comments [1] - Trackback
 |  | 

 Monday, November 27, 2006

Wie schon unter "Screenshots von Dynamics AX Masken erstellen" beschrieben, war es auch schon zu Dynamics AX 3.0 möglich, automatisierte Screenshots von Dynamics AX Masken erzeugen zu lassen, um diese dann später in seinen Dokumentationen zu verwenden.
Leider enthält Dynamics AX 4.0 die hierfür benötigten Klassen nicht mehr.

Allerdings soll bald ein Tool für Dynamics AX 4.0 erscheinen (TaskRecorder), welches diese und noch weitaus mehr Funktionalitäten bietet.
Wer sich dieses Toll einmal genauer ansehen möchte und einen PartnerSource-Zugang besitzt, der kann sich im PartnerSource eine Beta Version dieses Tools downloaden.
Genaue Informationen über den TaskRecoder (Features, Installation, etc.) können ebenfalls über das PartnerSource bezogen werden.

Nach meinen ersten Erfahrungen wird hiermit eine gute Basis geschaffen um eine einheitliche und schnell zu erstellende Dokumentation von Prozessen und Anpassungen zu erstellen.

Monday, November 27, 2006 10:16:27 PM (Mitteleuropäische Zeit, UTC+01:00)  Axel Kühn  #    Comments [0] - Trackback


 Tuesday, November 07, 2006

Wenn die MSDB Datenbank eines SQL Servers einen Datenbankfehler meldet und man
keine funktionierende / fehlerfreie Sicherung hat, stellt dies meist ein größeres Problem dar,
da diese nicht mit DBCC CHECKDB repariert werden kann.

 

Abhilfe schafft meist nur das neu Erstellen der gesamten MSDB Datenbank.

(Leider gehen hierbei unter anderem die eingerichteten Sicherungsjobs verloren)

 

Die MSDB kann wie folgt beschrieben neu erstellt werden (SQL Server 2000):

 

  1. Im SQL Server Enterprise Manager die Eigenschaften des Datenbankservers öffnen.
    (Rechtsklick auf den Datenbankserver -> Eigenschaften)
  2. Auf dem Reiter „Allgemein“ auf den Button „Startparameter“ klicken.
  3. Den Parameter "-T3608" hinzufügen.
  4. Den Datenbankserver stoppen und neu starten.
  5. Überprüfen, dass der SQL Server Agent gestoppt ist.
  6. Die MSDB Datenbank auswählen und über „Extras -> SQL Query Analyzer“ den QueryAnalyzer starten.
  7. Die MSDB Datenbank mit folgendem Skript abhängen

    use master
    go
    sp_detach_db ‚msdb’
    go

  8. Die defekte MSDB Datenbank (msdbdata.mdf, msdblog.ldf) löschen oder umbenennen (auf Fileebene).
  9. Das "instmsdb.sql" Skript mit dem QueryAnalyzer ausführen.
    (Liegt unter: …\Microsoft SQL Server\MSSQL\Install)
  10. Im SQL Server Enterprise Manager wieder den Startparameter "-T3608" entfernen.
  11. Den Datenbankserver stoppen und neu starten.

Jetzt sollte wieder eine funktionierende und fehlerfreie MSDB Datenbank vorliegen.

 

Bei einem SQL Server 2005 sollte dies genau so funktionieren.

Tuesday, November 07, 2006 2:41:21 PM (Mitteleuropäische Zeit, UTC+01:00)  Axel Kühn  #    Comments [0] - Trackback
 | 

 Monday, November 06, 2006

Ein weiteres Problem beim Update auf die neue Version Microsoft Dynamics AX 4.0 kann der Name des Unternehmenskontos sein.

Wird ein Unternehmenskonto verwendet, dass in seinem Namen ein „&“ enthält, z.B. „A&B“, werden einige Prozesse beim „Datenaktualisierung nachsynchronisieren“ mit einem Fehler abgebrochen.

Im Ereignislog ist dann ein Eintrag des Dynamics AX 4.0 Servers zu finden, der wie folgt lautet (Ausschnitt):

„…[Microsoft][ODBC SQL Server Driver][SQL Server]Falsche Syntax in der Nähe von '&'.. The SQL statement was…“

Daraus wird ersichtlich, das dass „&“ Zeichen als SQL Statement erkannt wird und die SQL Anweisung so fehlerhaft interpretiert wird.

Dieses Problem kann nur gelöst werden, indem man in dem zu updatenden Microsoft Dynamics AX 3.0 ein neues Unternehmenskonto erstellt das kein „&“ Zeichen beinhaltet (Am einfachsten geht dies mit der Dublizierfunktion der Unternehmenskonten).

Monday, November 06, 2006 4:52:54 PM (Mitteleuropäische Zeit, UTC+01:00)  admin  #    Comments [0] - Trackback
 |  | 

Für die Planung und Durchführung eines Updates stehen folgende Informationsquellen zur Verfügung:

  • Microsoft Dynamics AX Upgrade Tools Guide (PDF Dokument, Erhältlich im PartnerSource)
  • Microsoft Dynamics AX 4.0 Implementation Guide (CHM File, Dynamics AX 4.0 Dokumentation)
  • Inside Microsoft Dynamics AX 4.0 (Buch, Microsoft Press)

Diese enthalten eine gute Beschreibung der einzelnen Schritte die erforderlich sind, um von der Version 3.0 auf die Version 4.0 von Microsoft Dynamics AX zu updaten.

Allerdings können noch einige Probleme bei dem Updateprozess entstehen, die leider nicht Besprochen werden und für die auch in den bekannten Newsgroup, Blogs und Communitys noch keine Lösungsvorschläge gibt.

So sollte ein Upgrade immer in dem Layer durchgeführt werden, in dem die Anpassungen durchgeführt wurden (z.B. CUS oder VAR). Dies hat zur Folge das man u.U. die Anwendung mehrfach kompilieren muss, da man erst nach dem einlesen der Lizenzdatei zugriff auf diese Layer erhält.

Weiterhin kann man beim Durchführen der Synchronisierung folgenden Fehler erhalten:
"Cannot execute a data definition language command on (). The SQL database has issued an error."

Ursache hierfür kann sein, dass der  ConfigurationKey "CSESpain" ist in dem Microsoft Dynamics AX 3.0 System, welches geupdatet werden soll, nicht angeschaltet ist/war.
Dadurch sind drei Felder ("Action", "CustVendParameter", "CustVendAccount") der Tabelle "SalesPurchaseCycle" deaktiviert, die allerdings den eindeutigen Index "SalesPurchaseCycle" bilden. Dadurch werden Datensätze in die Tabelle geschrieben, die nicht dem eindeutigen Index entsprechen. Beim Update auf Microsoft Dynamics AX 4.0 wird dieser Index überprüft bzw. neu geschrieben und das Synchronisieren wird mit einem Fehler abgebrochen, da die Datensätze der Tabelle nicht eindeutig sind.

Das Problem kann gelöst werden, indem man auf der Tabelle "SalesPurchaseCycle" den eindeutigen Index "SalesPurchaseCycleIdx" auf "Enabled = NO" setzt.
Anschließend sollten alle Datensätze in dieser  Tabelle in allen Unternehmen gelöscht werden und der Index "SalesPurchaseCycleIdx" wieder auf "Enabled = YES" gesetzt werden.

Die Deaktivierung des ConfigurationKey "CSESpain" reicht leider nicht aus, da es dann zu Problemen beim "Datenaktualiserung nachsynchronisieren" kommen kann, da dort die einzelnen Datensätze überprüft werden (5 Prozesse werden deswegen mit einem Fehler beendet).

Weiterhin sei noch angemerkt, dass alle Anpassungen in Bereich der "Forms" zu erheblichen Problemen beim Codeupgrade führen können.
Viele Formelemente wurden in der neuen Version 4.0 unbenannt, was dazu führen kann, dass eine einzige Anpassung (z.B. Änderung nur einer Formproperty) mehrere hundert Fehler erzeugen kann.

Bsp.: Änderung einer Property der Form "CompanyInfo" im upzudatenden Microsoft Dynamics AX 3.0 System führte zu 126 Fehlern im Microsoft Dynamics AX 4.0 System.

Deswegen sollte man vor einem Update genauestens überlegen/überprüfen, ob es überhaupt Sinn macht die getätigten Anpassungen mit zur neuen Version (4.0) zu migrieren.

Oft können getätigte Anpassungen durch Erweiterungen im Standard abgelöst werden, die eine ähnliche Funktionalität bieten. In machen Fällen ist es unter Berücksichtigung der benötigten Zeit sogar Sinnvoller, die Anpassung erneut im Microsoft Dynamics AX 4.0 System vorzunehmen.

Eine Migration der Anpassungen sollte nur in Erwägung gezogen werden, wenn keine andere Lösung gefunden werden kann.

Monday, November 06, 2006 3:47:54 PM (Mitteleuropäische Zeit, UTC+01:00)  Axel Kühn  #    Comments [0] - Trackback
 |  | 

 Thursday, September 21, 2006

Auszug aus der aktuellen Pressemitteilung von Microsoft:

Microsoft gibt Startschuss für Microsoft Dynamics AX 4.0

Microsoft bietet die neue Version der kaufmännischen Software Microsoft Dynamics AX ab sofort auf dem deutschen Markt an. Microsoft Dynamics AX 4.0 ist eine anpassbare Businessmanagementlösung, die Unternehmen hilft, fundierte und profitable Geschäftsentscheidungen zu treffen. Die Software, deren Nutzeroberfläche allen anderen Produkten von Microsoft gleicht, lässt sich nahtlos mit Microsoft Office 2003 und der Microsoft Windows Server System-Familie verzahnen. Microsoft Dynamics AX 4.0 richtet sich an mittelständische Unternehmen und den gehobenen Mittelstand.

mehr unter:

http://www.microsoft.com/germany/presseservice/detail.mspx?id=531742

Thursday, September 21, 2006 4:46:42 PM (Mitteleuropäische Zeit, UTC+01:00)  Axel Kühn  #    Comments [0] - Trackback
 | 

 Tuesday, September 19, 2006

Im Mai 2007 soll im Vieweg Verlag ein neues Buch über Microsoft Dynamics AX 4.0 erscheinen.

Der Schwerpunkt des Buches soll auf den Grundlagen von Dynamics Ax 4.0 und den Neuerungen zur Vorgängerversion liegen.
Genaueres ist noch nicht bekannt.

Tuesday, September 19, 2006 10:14:12 AM (Mitteleuropäische Zeit, UTC+01:00)  Axel Kühn  #    Comments [0] - Trackback
 | 

 Thursday, September 14, 2006

Oft wird ein Export von Dynamics AX Daten in ein Exceldokument benötigt. Z.B. für einfache Auswertungen oder für Datenimporte in andere Systeme.

Hier ein kurzes Beispiel, wie man aus Dynamics AX ein neues Exceldokument per Code erstellen kann.

static void CreateExcelDokument(Args _args)
{
   SysExcelApplication xlsApplication;
   SysExcelWorkBooks xlsWorkBookCollection;
   SysExcelWorkBook xlsWorkBook;
   SysExcelWorkSheets xlsWorkSheetCollection;
   SysExcelWorkSheet xlsWorkSheet;
   SysExcelRange xlsRange;
   CustTable custTable;
   int row = 1;
   str fileName;
   ;
   // Name des Exceldokuments.
   fileName = "C:\\test.xsl";

   // Excel initalisieren und öffnen.
   xlsApplication = SysExcelApplication::construct();
   xlsApplication.visible(true);

   // Neues Excel Worksheet erzeugen.
   xlsWorkBookCollection = xlsApplication.workbooks();
   xlsWorkBook = xlsWorkBookCollection.add();
   xlsWorkSheetCollection = xlsWorkBook.worksheets();
   xlsWorkSheet = xlsWorkSheetCollection.itemFromNum(1);

   // Zellenüberschriften in das Worksheet schreiben.
   xlsWorkSheet.cells().item(row,1).value('Account Num');
   xlsWorkSheet.cells().item(row,2).value('Name');

   row++;

   // Excel Worksheet mit Daten füllen (Excel-Zellen füllen).
   while select custTable
   {
      xlsWorkSheet.cells().item(row,1).value(custTable.AccountNum);
      xlsWorkSheet.cells().item(row,2).value(custTable.Name);
      row++;
   }

   // Prüfen ob das Dokument schon existiert.
   if(WinApi::fileExists(fileName))
   {
      WinApi::deleteFile(fileName);
   }

   // Excel Dokument speichern.
   xlsWorkbook.saveAs(fileName);

   // Excel schließen.
   xlsApplication.quit();
   xlsApplication.finalize();
}


 

Thursday, September 14, 2006 9:54:10 AM (Mitteleuropäische Zeit, UTC+01:00)  Axel Kühn  #    Comments [1] - Trackback
 | 

 Monday, August 14, 2006

Seit ende Juli / Anfang August steht auch die lokalisierten Versionen von Microsoft Dynamics AX 4.0 für Microsoft Partner bereit, die einen PartnerSource Zugang haben.

Lokalisierungen stehen u.a. für volgende Länder zur Verfügung

Denmark
France
Germany
Great Britain
Ireland

Eine ausführliche Liste ist ebenfalls im PartnerSource erhältlich.

Monday, August 14, 2006 6:00:53 PM (Mitteleuropäische Zeit, UTC+01:00)  Axel Kühn  #    Comments [0] - Trackback


 Friday, July 28, 2006

Wer auf der Suche nach Dokumentation zu / über Dynamics Ax 4.0 ist, sollte mal einen Blick auf diese Seite werfen:
Using Microsoft Dynamics AX

Friday, July 28, 2006 6:57:07 PM (Mitteleuropäische Zeit, UTC+01:00)  Axel Kühn  #    Comments [0] - Trackback
 |  | 

 Thursday, July 27, 2006

Um den Text, der in der Titelleiste des Dynamics AX Clients angezeigt wird, zu ändern muss man folgendes machen:

  1. Auf dem Clientrechner in das Axapta Client Installationsverzeichnis wechseln.
  2. Im Unterverzeichnis "Client\Bin" die Datei "Axsys$$.KTD" mit einem Texteditor öffnen.
    ($$ steht hierbei für das entsprechde Länderkürzel. Z.B. de)  
  3. Das Label "#1076" wie gewünscht anpassen.

Nach einem (Neu)Start des Dynamics AX Clients wird nun der in dem Label eingetragene Text in der Titelleiste des Dynamics AX Clients angezeigt.

Thursday, July 27, 2006 3:39:29 PM (Mitteleuropäische Zeit, UTC+01:00)  Axel Kühn  #    Comments [0] - Trackback
 | 

Mit dieser Property lässt sich bestimmen, ob ein Feld ein Eingabe- oder Suchfeld sein soll.
Dies ist gerade bei der Verwendung von Gridcontrols hilfreich, da keine zusätzlichen Filter- oder Suchfunktionen eingebaut werden müssen.

 

Die Property kann folgende Werte annehmen:

  • None

Eingaben in diesem Feld ist möglich. Das Feld ist somit ein Eingabe und kein Suchfeld

  • Search After Input

Das Feld ist ein Suchfeld. Eingaben in die Datenbank sind über dieses Feld nicht mehr möglich.

Wird in dem Feld eine Eingabe vorgenommen, wird nach dem Verlassen des Datensatzes eine Abfrage der Datenbank durchgeführt. Es werden der Feldeingabe entsprechende Datensätze angezeigt. Es wird auf den eingegebenen Wert gefiltert.

  • Search On Typing

Das Feld ist ein Suchfeld. Eingaben in die Datenbank sind über dieses Feld nicht mehr möglich.

Sobald in diesem Feld eine Eingabe erfolgt, wird automatisch zu dem der Eingabe entsprechenden Datensatz gesprungen. Gleiches verhalten wie im AOT.

 

Thursday, July 27, 2006 9:55:53 AM (Mitteleuropäische Zeit, UTC+01:00)  admin  #    Comments [0] - Trackback


 Wednesday, July 19, 2006

Es ist nicht gerade einfach, einen Screenshot einer einzelnen Maske (z.B. Debitoren) von Dynamics Ax zu erstellen.

Verwendet man die Windows-Boardmittel, ist in dem erzeugten Screenshot immer der gesamte Dynamics AX Bildschirm enthalten. Da Dynamics AX eine MDI Anwendung ist, erkennt Windows immer nur den gesamten Dynamics AX Bildschirm und nicht wie gewollt, die in diesem "Hauptbildschirm" aktive Dynamics AX Maske (z.B. Debitoren).

Abhilfe kann hier mit zahlreichen zusätzlichen Tools geschaffen werden, die es ermöglichen, nur einen bestimmten Bildschirmausschnitt in den Screenshot zu übernehmen (z.B. Hardcopy oder Paintshop Pro).

Aber geht das nicht doch etwas einfacher?

Klare Aussage: Ja es geht einfacher!
Dynamics AX ist in der Lage, automatisch von einer oder mehreren Masken gleichzeitig (natürlich einzeln und nacheinander) Screenshots zu erzeugen.