Danjo's two cents NAV, Powershell, Android, C#, Lync, Win8, …

27Jan/150

Systemindikator

Der mit NAV 2009 eingeführte Systemindikator kann neun verschiedene Akzente annehmen.

Wobei Akzente lediglich für die Farbgestaltung steht. Der Standard entspricht "Accent9".

Da das Wechseln des Akzentes nur nach dem Neustart des RTC zu sehen ist, dauert das durchprobieren immer etwas.

Um mir das zu ersparen habe ich einmal alle Akzente in einer Grafik abgespeichert.

SI_Total

Viel Spaß damit Cheeze

25Jan/150

NAV 2013 (R2) – Benutzer los werden

In NAV gibt es seit Jahr und Tag eine feste Regel:

Gibt es keine Benutzer darf jeder die Applikation benutzen.

Das ist besonders dann hilfreich, wenn man gerade vom Kunden eine Datenbank bekommen hat, zu der man keinen Login kennt.

Und dank SQL haben wir auch dann noch die Möglichkeit die Benutzer los zu werden, wenn wir gar keinen der angelegten Benutzer kennen.

Am schnellsten geht das über ein paar SQL-Befehle:

Anschliessend muss nur noch das Service-Tier neu gestartet werden.

24Okt/140

NAV 2013 R2 – Änderungen werden erst nach Neustart des ServiceTiers aktiv

Diese Woche bin ich auf ein eher störendes Phänomen bei der Entwicklung in einer NAV 2013 R2 CU12 Datenbank gestosen. (Das verhalten konnte ich inzwischen auch in älteren Build-Versionen nachstellen)

Ich lege eine neue Tabelle an, erzeuge eine Page dazu und klicke auf RUN.

SQL-Fehler: Tabelle kann nicht gefunden werden.

Kurzer Blick auf dem Server, die Tabelle fehlt tatsächlich.

Export -> Lösche -> Import -> Tabelle fehlt

Sync-NAVTenant im Powershell aufrufen -> kein Fehler -> Tabelle fehlt

Neustart NST -> Tabelle fehlt -> Start RTC -> Tabelle wird angelegt

 

Diese Verhalten war Problemlos jederzeit reproduzierbar. Doch wo kam es her? An CU12 scheint es nicht zu liegen.

Fragen wir doch mal das Internet: Keine der üblichen Suchen bringt etwas das helfen könnte.

Dann hat es mir doch noch gedämmert: Es sieht so aus als ob der Trigger in der Object Metadata Tabelle fehlt.

Kurzer Blick: Stimmt, der ist nicht da.

 

Wie habe ich das den geschafft?

Mein Vorgehen war so:

- Neue Datenbank über SQL anlegen

- Import einer NAVDATA-Sicherung inkl. aller Objekte und Daten

 

In der Dev-Enviroment sieht alles gut aus. Der RTC läuft auch stabil.

 

Zum Schluß dann noch wie das ganze zu korrigieren ist:

Der Trigger lässt sich über SQL anlegen:

/****** Object: Trigger [dbo].[$ndo$objecttracking] Script Date: 23.10.2014 08:38:20 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TRIGGER [dbo].[$ndo$objecttracking] ON [dbo].[Object Metadata] FOR DELETE, INSERT, UPDATE AS SET NOCOUNT ON DECLARE @delCount INTEGER, @insCount INTEGER, @updatedRows INTEGER, @currentDBTS BIGINT SELECT @delCount = COUNT(*) FROM DELETED SELECT @insCount = COUNT(*) FROM INSERTED SELECT @updatedRows = 0 SELECT @currentDBTS = CAST(@@DBTS AS BIGINT) IF (@insCount > 0) BEGIN UPDATE [dbo].[Object Tracking] SET [Object Timestamp] = @currentDBTS FROM INSERTED AS I JOIN [dbo].[Object Tracking] AS T ON (T.[Object Type] = I.[Object Type] AND T.[Object ID] = I.[Object ID] AND T.[Change Type] = 0) SELECT @updatedRows = @@ROWCOUNT IF (@updatedRows < @insCount) BEGIN INSERT INTO [dbo].[Object Tracking] ([Object Type], [Object ID], [Change Type], [Object Timestamp]) SELECT I.[Object Type], I.[Object ID], 0, @currentDBTS FROM INSERTED AS I LEFT OUTER JOIN [dbo].[Object Tracking] AS T ON (I.[Object Type] = T.[Object Type] AND I.[Object ID] = T.[Object ID] AND T.[Change Type] = 0) WHERE T.[Object Type] IS NULL AND T.[Object ID] IS NULL END END IF (@delCount > 0) BEGIN IF (@updatedRows = 0) BEGIN UPDATE [dbo].[Object Tracking] SET [Object Timestamp] = @currentDBTS FROM DELETED AS D JOIN [dbo].[Object Tracking] AS T ON (T.[Object Type] = D.[Object Type] AND T.[Object ID] = D.[Object ID] AND T.[Change Type] = 0) SELECT @updatedRows = @@ROWCOUNT END IF (@updatedRows < @delCount) BEGIN INSERT INTO [dbo].[Object Tracking] ([Object Type], [Object ID], [Change Type], [Object Timestamp]) SELECT D.[Object Type], D.[Object ID], 0, @currentDBTS FROM DELETED AS D LEFT OUTER JOIN [dbo].[Object Tracking] AS T ON (D.[Object Type] = T.[Object Type] AND D.[Object ID] = T.[Object ID] AND T.[Change Type] = 0) WHERE T.[Object Type] IS NULL AND T.[Object ID] IS NULL END END GO

30Okt/120

Dynamics Technical Airlift – Das SQL-Statement hinter der Query

Während meines Vortrages habe ich ein SQL-Statement gezeigt, welches mit dem SQL-Profiler während der Laufzeit einer Query aufgezeichnet wurde.

Hierbei handelt es sich um eine Query, welche das selbe Ergebnis liefert wie der TOP-10-Debitoren-Report. Die Query benötigt gerade in großen Datenbank merklich weniger Zeit.

Hier noch einmal das SQL-Statement zum nachlesen:

SELECT TOP (10) ISNULL("Customer"."No_",@0) AS "No",ISNULL("Customer"."Name",@1) AS "Name",ISNULL(SUM("SUB$Customer$Sales (LCY)"."Sales (LCY)$Cust_ Ledger Entry$SUM$Sales (LCY)"),@3) AS "Sum_Sales_LCY",ISNULL(SUM("SUB$Customer$Balance (LCY)"."Balance (LCY)$Detailed Cust_ Ledg_ Entry$SUM$Amount (LCY)"),@5) AS "Sum_Balance_LCY" FROM "Demo Database NAV (7-0)"."dbo"."CRONUS AG$Customer" AS "Customer" WITH(READUNCOMMITTED)

OUTER APPLY (SELECT TOP (1) ISNULL(SUM("Sales (LCY)$Cust_ Ledger Entry"."Sales (LCY)"),@2) AS "Sales (LCY)$Cust_ Ledger Entry$SUM$Sales (LCY)" FROM "Demo Database NAV (7-0)"."dbo"."CRONUS AG$Cust_ Ledger Entry" AS "Sales (LCY)$Cust_ Ledger Entry" WITH(READUNCOMMITTED)  WHERE ("Sales (LCY)$Cust_ Ledger Entry"."Customer No_"="Customer"."No_")) AS "SUB$Customer$Sales (LCY)"

OUTER APPLY (SELECT TOP (1) ISNULL(SUM("Balance (LCY)$Detailed Cust_ Ledg_ Entry"."Amount (LCY)"),@4) AS "Balance (LCY)$Detailed Cust_ Ledg_ Entry$SUM$Amount (LCY)" FROM "Demo Database NAV (7-0)"."dbo"."CRONUS AG$Detailed Cust_ Ledg_ Entry" AS "Balance (LCY)$Detailed Cust_ Ledg_ Entry" WITH(READUNCOMMITTED)  WHERE ("Balance (LCY)$Detailed Cust_ Ledg_ Entry"."Customer No_"="Customer"."No_")) AS "SUB$Customer$Balance (LCY)"

ORDER BY "Sales_LCY" DESC,"No" ASC OPTION(OPTIMIZE FOR UNKNOWN, FAST 50, FORCE ORDER, LOOP JOIN)

Dies ist auch ein schönes Beispiel wie die Query im Hintergrund mit verschachtelten Abfragen, der TOP-Klausel und den SQL eigenen Funktionen wie SUM arbeitet.

23Okt/121

NAV2013 – Zugriff auf OData

Habt ihr schon einmal die neuen Möglichkeiten mit OData ausprobiert die euch Microsoft Dynamics NAV 2013 bietet?

Hier einmal ein kurzer Überblick über die Zugriffsmöglichkeiten auf OData-Webservices.

Alle hier genannten Beispiele funktionieren mit der Standardinstallation von Cronus und dem veröffentlichten Webservice Customer mit dem Typ Seite und der ID 22.

 

Zeige alle OData-feeds:

http://localhost:7048/DynamicsNAV70/odata

Zeige Metadaten:

http://localhost:7048/DynamicsNAV70/odata/$metadata

Gib alle Debitoren aus:

http://localhost:7048/DynamicsNAV70/odata/Customer

Gib den Debitoren mit dem Primärschlüssel 10000 aus (Primärschlüssel verwenden):

http://localhost:7048/DynamicsNAV70/odata/Customer('10000')

Gib alle Debitoren mit dem Lagerort BLAU aus (Verwendung von Feldfiltern):

http://localhost:7048/DynamicsNAV70/odata/Customer?$filter=Location_Code eq 'BLAU'

Gib Name, Lagerortcode und Kreditlimit(MW) aus (Abruf einzelner Felder):

http://localhost:7048/DynamicsNAV70/odata/Customer?$select=Name, Location_Code, Credit_Limit_LCY

Gib Name, Lagerortcode und Kreditlimit (MW) für alle Debitoren aus der Lagerortcode BLAU ist (einzelne Felder kombiniert mit Filtern):

http://localhost:7048/DynamicsNAV70/odata/Customer?$filter=Location_Code eq 'BLAU' &$select=Name, Location_Code, Credit_Limit_LCY

%d Bloggern gefällt das: