Robert's Dynamics NAV/BC Entwickler Blog
Business Central HTML (RichContent) & Belegausgabe in RDLC
Mit Business Central 23 gibt es nun einen integrierten HTML Editor (Use the built-in rich text editor to enter data | Microsoft Learn). Diese wurde integriert für die Marketing Texte am Artikel. Dieser Editor kann aber auch in eigenen Entwicklungen genutzt werden. Mir stellten sich folgende Fragen: Zur Nutzung des neuen HTML Editor benötigt man… Weiterlesen » The post Business Central HTML (RichContent) & Belegausgabe in RDLC first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Mit Business Central 23 gibt es nun einen integrierten HTML Editor (Use the built-in rich text editor to enter data | Microsoft Learn). Diese wurde integriert für die Marketing Texte am Artikel. Dieser Editor kann aber auch in eigenen Entwicklungen genutzt werden. Mir stellten sich folgende Fragen: Wie kann neue HTML Editor in Individualisierungen genutzt werden? Wie kann der HTML Text gespeichert und gelesen werden? Wie sieht der HTML Text aus? Welche Logik wird für Zeilenumbrüche genutzt? Welche HTML Tags werden durch das RDLC nicht unterstützt und was passiert im Druck mit nicht unterstützten Tags? Gibt es eine Möglichkeit im HTML eingefügte Bilder im RDLC auszugeben? Zur Nutzung des neuen HTML Editor benötigt man lediglich eine Textvariable und den ExtendedDataType = „RichContent“. <img fetchpriority="high" decoding="async" width="851" height="229" src="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-1.png" alt="" class="wp-image-840" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-1.png 851w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-1-300x81.png 300w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-1-768x207.png 768w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-1-660x178.png 660w" sizes="(max-width: 851px) 100vw, 851px" /> So sieht der HTML Editor dann aus. Es ist zu berücksichtigen, dass ein HTML Feld mit dem ExtendedDatatype = RichContent, das einzige Feld in der Gruppe sein soll, damit die Seite korrekt gerendert werden. <img decoding="async" width="967" height="634" src="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-2.png" alt="" class="wp-image-843" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-2.png 967w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-2-300x197.png 300w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-2-768x504.png 768w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-2-660x433.png 660w" sizes="(max-width: 967px) 100vw, 967px" /> Dieser HTML Text hat keine Zeichenbegrenzung, daher empfiehlt es sich eine nicht begrenzte Textvariable zu nutzen. Muss der Text in der Datenbank gespeichert werden, dann kann dies in einem Blob gespeichert werden. Dafür können zum Lesen/Schreiben InStream und OutStream verwendet werden. Speichern in ein Blob Feld: <img decoding="async" width="850" height="463" src="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-3.png" alt="" class="wp-image-846" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-3.png 850w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-3-300x163.png 300w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-3-768x418.png 768w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-3-660x360.png 660w" sizes="(max-width: 850px) 100vw, 850px" /> Lesen aus einem Blob: Schauen wir uns den HTML Text an, dann kann man sehen, dass dort das HTML Tag für eine einzelne Zeile genutzt wird: <img loading="lazy" decoding="async" width="1024" height="591" src="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-1024x591.png" alt="" class="wp-image-850" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-1024x591.png 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-300x173.png 300w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-768x444.png 768w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-660x381.png 660w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image.png 1082w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /> Damit kann der Text in einzelne Teiltexte getrennt werden. Dafür kann beispielsweise folgende Funktion genutzt werden, die dann den HTML Text in eine Liste überträgt: Per Aktion können wir die Funktion nutzen um die Anzahl der Zeilen auszugeben: <img loading="lazy" decoding="async" width="832" height="228" src="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-6.png" alt="" class="wp-image-852" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-6.png 832w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-6-300x82.png 300w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-6-768x210.png 768w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-6-660x181.png 660w" sizes="auto, (max-width: 832px) 100vw, 832px" /> In unserem Beispiel haben wir 4 Zeilen: <img loading="lazy" decoding="async" width="1024" height="569" src="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-7-1024x569.png" alt="" class="wp-image-853" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-7-1024x569.png 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-7-300x167.png 300w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-7-768x427.png 768w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-7-660x367.png 660w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-7.png 1085w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /> Eine neue Zeile wird nur bei Enter gebildet. Die Ausgabe eines HTML Text in RDLC kann per Platzhalter ausgegeben werden. Es werden allerdings nur die folgenden Tags in RDLC unterstützt: Hyperlinks: <A href> Fonts: Header, style and block elements: <H{n}>, , , , , , <HN> Text format: , , , List handling: , , Das bedeutet, dass Farben oder auch Bilder in einem Ausdruck nicht dargestellt werden. Außerdem sollte berücksichtigt werden, dass die Übergabe eines langen HTML Textes an eine Textbox mit aktivierter HTML Interpretierung auch zusammengehalten wird. Überschreitet der Text den auf einer Seite zur Verfügung stehenden Seite, dann wird dieser einfach abgeschnitten. Daher kann die oben gezeigte Funktion mit der Liste genutzt werden um eine zeilenbasierte Ausgabe zu entwickeln. Dadurch wird das Rendering und die Ausgabe verbessert und der Platz besser genutzt. Testweise habe ich dazu einen Beleg angelegt. Dieser druckt die HTML Texte pro HTML Kopf und druckt die HTML Texte zeilenweise aus: <img loading="lazy" decoding="async" width="665" height="453" src="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-10.png" alt="" class="wp-image-857" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-10.png 665w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-10-300x204.png 300w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-10-660x450.png 660w" sizes="auto, (max-width: 665px) 100vw, 665px" /> Im Layout wird dann eine Tabelle mit der zeilenbasierten Texten ausgegeben und der Platzhalter besitzt den Markuptyp „HTML – HTML Tags als Formate interpretieren“: <img loading="lazy" decoding="async" width="1024" height="706" src="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-11-1024x706.png" alt="" class="wp-image-858" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-11-1024x706.png 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-11-300x207.png 300w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-11-768x530.png 768w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-11-660x455.png 660w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-11.png 1096w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /> Im HTML Editor werden einige Zeilen erfasst mit unterschiedlichen Formatierungen: <img loading="lazy" decoding="async" width="1024" height="409" src="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-12-1024x409.png" alt="" class="wp-image-859" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-12-1024x409.png 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-12-300x120.png 300w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-12-768x307.png 768w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-12-1536x614.png 1536w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-12-660x264.png 660w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-12.png 1654w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /> Im Druck sieht, dass Ganze so aus: <img loading="lazy" decoding="async" width="1024" height="385" src="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-8-1024x385.png" alt="" class="wp-image-855" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-8-1024x385.png 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-8-300x113.png 300w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-8-768x289.png 768w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-8-660x248.png 660w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-8.png 1205w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /> Die Ränder wurden auf Schwarz gesetzt, damit man sehen kann, dass die Texte aufgeteilt in einzelnen Textboxen gedruckt werden. Außerdem kann man sehen, dass das Bild nicht gedruckt wurde und einige HTML Tags nicht interpretiert werden (beispielsweise Hintergrundfarbe / Schriftfarbe). Demnach sind nicht unterstützte HTML Tags grundsätzlich kein Problem, da diese ignoriert werden. Zusätzlich gibt es die Möglichkeit Bilder aus dem HTML Text zu extrahieren und den Base64 Code an den RDLC Beleg zu übergeben. Hier kann dann ein Bildelement im RDLC genutzt werden um das Bild auszugeben. Dabei ist zu berücksichtigen, dass Bilder nur in separaten Zeilen ausgegeben werden können und nicht nebeneinander. Auch ist die Größe der Bilder nicht so einfach anpassbar. Bilder in RDLC sind statisch und können damit nicht „flexibel“ groß sein. Bilder können über den HTML Tag erkannt werden. Allerdings ist es möglich über die Codeunit Image die Höhe und die Breite eines Bilder zu ermitteln. Mit diesen Informationen können in einer RDLC Tabelle mehrere Zeilen mit unterschiedlichen Höhen angegeben werden (Pixelhöhe 50, 100, 200, 300, 400, 500, …). Das Bild wird dennoch etwas skaliert, da die Höhe des Bildes nicht generisch wachsen oder schrumpfen kann. Dennoch ist es so möglich, dass ein Output die Bilder nahezu in der ursprünglichen Größe ausgegeben werden ohne leeren Platz im Druck zu erzeugen. Hier gibt es ein Beispiel um die Größe des ersten Bildes des HTML Textes zu ermitteln: <img loading="lazy" decoding="async" width="988" height="394" src="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-13.png" alt="" class="wp-image-860" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-13.png 988w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-13-300x120.png 300w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-13-768x306.png 768w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-13-660x263.png 660w" sizes="auto, (max-width: 988px) 100vw, 988px" /> <img loading="lazy" decoding="async" width="1024" height="586" src="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-14-1024x586.png" alt="" class="wp-image-861" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-14-1024x586.png 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-14-300x172.png 300w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-14-768x439.png 768w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-14-660x377.png 660w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-14.png 1182w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /> Um eine Ausgabe eines Bildes im Bericht zu implementieren, wird eine Funktion benötigt, die die Bilder in einem HTML Text erkennt, extrahiert und separat an das RDLC Layout übergibt. So könnte das aussehen: <img loading="lazy" decoding="async" width="669" height="495" src="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-18.png" alt="" class="wp-image-867" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-18.png 669w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-18-300x222.png 300w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-18-660x488.png 660w" sizes="auto, (max-width: 669px) 100vw, 669px" /> Dies erstellt eine Liste mit den Base64 Codes der Bilder zu einem HTML Text. Im Bericht kann dann ein weiteres Integer DataItem eingefügt werden, welches die Bilder für eine einzelne HTML Zeile ermittelt und diese dann zusammen mit der Bildhöhe an RDLC übergibt. <img loading="lazy" decoding="async" width="1024" height="279" src="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-16-1024x279.png" alt="" class="wp-image-864" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-16-1024x279.png 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-16-300x82.png 300w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-16-768x209.png 768w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-16-660x180.png 660w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-16.png 1507w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /> <img loading="lazy" decoding="async" width="1024" height="686" src="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-15-1024x686.png" alt="" class="wp-image-863" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-15-1024x686.png 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-15-300x201.png 300w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-15-768x515.png 768w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-15-660x442.png 660w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-15.png 1219w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /> Es ist zu beachten, dass diese Logik ihre Grenzen hat, aber für einige Anwendungsfälle evtl. nutzbar. Im RDLC gibt es dafür einfach mehrere Zeilen in der Tabelle mit unterschiedlich großen Bildern und das Bild wird dann in der Zeile gerendert, die ungefähr die gleiche Größe hat. Alle anderen Zeilen werden ausgeblendet: <img loading="lazy" decoding="async" width="745" height="727" src="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-17.png" alt="" class="wp-image-865" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-17.png 745w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-17-300x293.png 300w, https://robert-dynamicsnav.de/wp-content/uploads/2023/12/image-17-660x644.png 660w" sizes="auto, (max-width: 745px) 100vw, 745px" /> Im Programmcode selbst muss nur geprüft werden, welche Höhe das Bild hat und basierend darauf die richtige Zeile gedruckt werden. Ich sehe sonst keinen anderen Weg Bilder aus dem HTML Editor ansatzweise in der richtigen Größe in RDLC zu drucken. Persönliche Meinung Der HTML Editor an sich ist top. Dies ohne Addin im Webclient nutzen zu können ist wirklich gut. Die Integration in Belege ist aber noch nicht vollständig möglich. Es gibt dazu bereits unterschiedlichste Anfragen in den BC Ideas. Wenn mehr HTML Tags im RDLC unterstützt werden, könnte diese Funktionalität tatsächlich interessant werden. Ansonsten sollte auf die Integration der HTML Texte im RDLC verzichtet oder nur in abgegrenzten Fällen genutzt werden. The post Business Central HTML (RichContent) & Belegausgabe in RDLC first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Dynamics NAV / Business Central mit einer PostgreSQL Datenbank verbinden
Hallo zusammen, wie kann eine PostgreSQL Datenbank in Dynamics NAV / Dynamics Business Central angebunden werden? Genau vor dieser Frage standen meine Kollegen und ich in einem Projekt. Für mich lagen drei Lösungsansätze auf der Hand: Option 1: Verbindung per .NET Integration (Service Tier verbindet sich zu der PostgreSQL Datenbank) Option 2: Verbindung des Microsoft… Weiterlesen » The post Dynamics NAV / Business Central mit einer PostgreSQL Datenbank verbinden first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Hallo zusammen, wie kann eine PostgreSQL Datenbank in Dynamics NAV / Dynamics Business Central angebunden werden? Genau vor dieser Frage standen meine Kollegen und ich in einem Projekt. Für mich lagen drei Lösungsansätze auf der Hand: Option 1: Verbindung per .NET Integration (Service Tier verbindet sich zu der PostgreSQL Datenbank) Option 2: Verbindung des Microsoft SQL Servers zu der PostgreSQL Datenbank Option 3: Nutzung einer REST api um Daten per Web Service von der PostgreSQL Datenbank lesen zu können. Auf Option 3 gehe ich in diesem Blog nicht ein, da es zum Thema REST mit Dynamics NAV / BC eigentlich schon genug Informationen gibt. Für Option 1 und 2 wird als Basis ein separater Treiber benötigt. Microsoft SQL Server kann nicht direkt ohne Treiber mit einer PostgreSQL Datenbank verbunden werden. Ich habe mich für diesen Treiber entschieden: https://odbc.postgresql.org/ Ich empfehle die 64-bit Variante des Treibers. Die Installation des Treibers sollte als Administrator ausgeführt werden. Die Installation sollte dort installiert werden, wo dieser später auch benutzt wird. Beispiele: Möchte ich eine Verbindung von SQL Server zu der PostgreSQL Datenbank aufbauen, dann muss der Treiber auf dem SQL Server installiert werden. Möchte ich eine Verbindung über die Service Tier (beispielsweise per Task Scheduler) aufbauen, dann muss der Treiber auf der Maschine der Service Tier installiert werden. Installation des ODBC Treibers Die Installation ist einfach durchzuführen. Starte die Installation und klicke auf „Weiter“ (Next): <img loading="lazy" decoding="async" class="alignnone wp-image-728 size-full" src="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLInstallation1.png" alt="" width="496" height="387" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLInstallation1.png 496w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLInstallation1-300x234.png 300w" sizes="auto, (max-width: 496px) 100vw, 496px" /> Akzeptiere nach dem Lesen die „License Agreement“: <img loading="lazy" decoding="async" class="alignnone wp-image-729 size-full" src="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLInstallation2.png" alt="" width="496" height="388" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLInstallation2.png 496w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLInstallation2-300x235.png 300w" sizes="auto, (max-width: 496px) 100vw, 496px" /> Anschließend können die Module ausgewählt werden. Die Dokumentation ist optional: <img loading="lazy" decoding="async" class="alignnone wp-image-730 size-full" src="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLInstallation3.png" alt="" width="497" height="385" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLInstallation3.png 497w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLInstallation3-300x232.png 300w" sizes="auto, (max-width: 497px) 100vw, 497px" /> Die Installation wird anschließend ausgeführt und benötigt Adminrechte. <img loading="lazy" decoding="async" class="alignnone wp-image-731 size-full" src="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLInstallation4.png" alt="" width="497" height="385" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLInstallation4.png 497w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLInstallation4-300x232.png 300w" sizes="auto, (max-width: 497px) 100vw, 497px" /> <img loading="lazy" decoding="async" class="alignnone wp-image-732 size-full" src="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLInstallation5.png" alt="" width="498" height="384" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLInstallation5.png 498w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLInstallation5-300x231.png 300w" sizes="auto, (max-width: 498px) 100vw, 498px" /> Nach der Installation können wir die Verbindung testen. Dafür können wir das Feature „System DNS“ von Windows Server nutzen. Dazu muss auf dem Windows Server der „Server Manager“ geöffnet werden. <img loading="lazy" decoding="async" class="alignnone wp-image-733 size-full" src="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLServerManager.png" alt="" width="384" height="120" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLServerManager.png 384w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLServerManager-300x94.png 300w" sizes="auto, (max-width: 384px) 100vw, 384px" /> Im Server Manager können wir über Tools die Option „ODBC Data Sources (64-bit)“ auswählen: <img loading="lazy" decoding="async" class="alignnone wp-image-734 size-full" src="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLServerManagerODBCDataSource.png" alt="" width="1422" height="360" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLServerManagerODBCDataSource.png 1422w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLServerManagerODBCDataSource-300x76.png 300w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLServerManagerODBCDataSource-1024x259.png 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLServerManagerODBCDataSource-768x194.png 768w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLServerManagerODBCDataSource-665x168.png 665w" sizes="auto, (max-width: 1422px) 100vw, 1422px" /> In dem neuen Fenster wählen wir den Reiter System DSN aus. <img loading="lazy" decoding="async" class="alignnone wp-image-735 size-full" src="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLServerManagerSystemDNS.png" alt="" width="592" height="422" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLServerManagerSystemDNS.png 592w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLServerManagerSystemDNS-300x214.png 300w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLServerManagerSystemDNS-60x42.png 60w" sizes="auto, (max-width: 592px) 100vw, 592px" /> Hier können wir nun einen neuen Eintrag hinzufügen. Dazu klicken wir auf „Add“ (Hinzufügen). Wir wählen anschließend den Treiber „PostgreSQL Unicode (x64)“ aus: <img loading="lazy" decoding="async" class="alignnone wp-image-736 size-full" src="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLServerManagerSystemDNSTreiberAuswahl.png" alt="" width="462" height="347" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLServerManagerSystemDNSTreiberAuswahl.png 462w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLServerManagerSystemDNSTreiberAuswahl-300x225.png 300w" sizes="auto, (max-width: 462px) 100vw, 462px" /> Die folgenden Werte sollten ausgefüllt werden: Data Source: Gibt den generellen Namen an. Ich empfehle einen einfachen Namen, da dieser später wiederverwendet wird (in Linked Server des SQL Servers oder auch in Dynamics NAV). Database: Muss den exakt korrekten Namen der PostgreSQL Datenbank beinhalten. Server: Sollte den DNS Namen oder die IP des PostgreSQL Servers beinhalten. Username: Benutzername des Logins Description: Das ist optional, kann aber helfen eine bessere Übersicht über die Datenquellen zu schaffen, wenn Verbindungen zu vielen verschiedenen Datenbanken existieren. SSL Mode: Das hängt stark von der Konfiguration der PostgreSQL Datenbank ab, allerdings sollte dies mindestens auf „require“ stehen um die Verbindung sicher zu machen. Port: Port des PostgreSQL Servers. Der Standardport ist 5432. Password: Passwort für den Benutzernamen. Anschließend sollten die Einstellungen gespeichert werden. Der Treiber kann innerhalb der Option „Datasource“ / „Global“ noch eingestellt werden. Dort werden auch immer wieder Optionen verbessert. Es lohnt sich daher von Zeit zu Zeit auch den Treiber zu aktualisieren, falls ein bestimmtes Problem besteht. Beispielsweise kann über den Treiber gesteuert werden, ob boolean Felder als integer (mit 0 oder 1) oder als Chars übertragen werden. <img loading="lazy" decoding="async" class="alignnone wp-image-737 size-full" src="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLServerManagerSystemDNSDataSource1.png" alt="" width="432" height="377" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLServerManagerSystemDNSDataSource1.png 432w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLServerManagerSystemDNSDataSource1-300x262.png 300w" sizes="auto, (max-width: 432px) 100vw, 432px" /> Bei Probleme mit dem Treiber lohnt sich ein Blick ins Wiki oder in dafür spezialisierten Foren (beispielsweise: https://www.pg-forum.de) Nach der Einstellung der Verbindungsparameter kann der Treiber mit der Aktion „Test“ geprüft werden: Sobald die Verbindung mit System DNS funktioniert, sollte auch die Verbindung mit dem SQL Server oder mit Dynamics NAV funktionieren. Das ist die bereits die halbe Miete. Sollte die Verbindung nicht klappen, sollte generell geprüft werden, ob der PostgreSQL Server erreichbar ist. Wird dieser in der Cloud gehostet sind ggf. IP Freigaben notwendig um überhaupt eine Verbindung aufbauen zu können. Zugriff auf die PostgreSQL Datenbank mit pgAdmin Empfehlenswert ist ebenfalls ein Tool um auf die PostgreSQL Datenbank zugreifen zu können. Dafür habe ich pgadmin verwendet, da es übersichtlich und einfach ist. https://www.pgadmin.org Hinweis: Ich hatte Probleme mit pgAdmin in der Verwendung des Internet Explorers. Vermutlich müssen einige Skripte in den Internet Einstellung aktiviert werden. Mit anderen Browsern klappt es ohne Probleme. <img loading="lazy" decoding="async" class="alignnone wp-image-740 size-full" src="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLpgadmin.png" alt="" width="809" height="957" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLpgadmin.png 809w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLpgadmin-254x300.png 254w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLpgadmin-768x908.png 768w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQLpgadmin-665x787.png 665w" sizes="auto, (max-width: 809px) 100vw, 809px" /> Zugriff auf die PostgreSQL Datenbank per SQL Server Im SQL Server Management Studio können wir eine Verbindung per „Linked Server“ aufbauen. <img loading="lazy" decoding="async" class="alignnone wp-image-741 size-full" src="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_SQLServerLinkedServer1.jpg" alt="" width="336" height="229" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_SQLServerLinkedServer1.jpg 336w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_SQLServerLinkedServer1-300x204.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_SQLServerLinkedServer1-60x42.jpg 60w" sizes="auto, (max-width: 336px) 100vw, 336px" /> Dazu erstellen wir einen neuen Linked Server und wählen die folgenden Einstellungen: Linked server: Name des Linked Servers – kann frei vergeben werden. Keine Leerzeichen oder Sonderzeichen verwenden um spätere Probleme zu vermeiden. Provider: Microsoft OLE OD Provider for ODBC Drivers Product name: optional Data source: Hier benutzen wir den exakt gleichen Namen, den wir in den System DNS Einstellungen angegeben haben. Provider string: optional Location: optional Catalog: optional Unter Sicherheit/Security sollte die Option „be made using this security context“ ausgewählt werden. Benutzername und Password müssen hier erneut eingegeben werden. <img loading="lazy" decoding="async" class="alignnone wp-image-742 size-full" src="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_SQLServerLinkedServer2.jpg" alt="" width="699" height="682" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_SQLServerLinkedServer2.jpg 699w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_SQLServerLinkedServer2-300x293.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_SQLServerLinkedServer2-665x649.jpg 665w" sizes="auto, (max-width: 699px) 100vw, 699px" /> Nach der Einrichtung des Linked Servers kann per Rechtsklick „Test Connection“ ausgewählt werden. Die Verbindung sollte auch hier erfolgreich sein. Auch sollte man unter Catalogs die PostgreSQL Datenbank sehen und unter Tables die einzelnen PostgreSQL Tabellen. Es gibt auch die Möglichkeit per Connection String den SQL Server mit der PostgreSQL Datenbank zu verbinden. In diesem Fall ist keine Konfiguration in den System DNS Einstellungen notwendig. Zum Lesen der PostgreSQL Tabellen wird immer ein Skript benötigt. Beispiel: SELECT number ISNULL(name), 100), '') as name, ISNULL(email), 80), '') as email, ISNULL(CAST(active_customer as tinyint), 0) as active_customer, CONVERT(VARCHAR,ISNULL(updated_at, CAST('1753-01-01 00:00:00:000' as datetime2))) as updated_at FROM OPENQUERY(NAVLinkedServer, 'SELECT number, name::varchar(255), email::varchar(1000), active_customer, updated_at FROM public.customers'); GO Wir benötigen den Befehl OPENQUERY, da wir mit einem normalen Skript nicht alle Datentypen korrekt lesen können und höchstwahrscheinlich Probleme bekommen. Allerdings hat OPENQUERY auch den Nachteil, das das SELECT Statement nur statisch mit einer WHERE Klausel eingeschränkt werden kann. Erstellen wir hieraus eine View und verknüpfen diese mit einer Tabelle in NAV werden wir immer das gleiche SELECT Statement verwenden um aus der PostgreSQL Tabelle Daten zu lesen. Sollte man mit Tabellen arbeiten, die immer mehr Daten beinhalten, dann ist die Option möglicherweise nicht sinnvoll. Außerdem muss hier der Transaction Type in NAV geändert werden. Der Standard ist ReadNoLocks. Das wird aber dazu führen, das in dem SQL SELECT ein „BEGIN DISTRIBUTED TRAN“ ergänzt wird. Das wird von PostgreSQL nicht unterstützt. Demnach muss der TransactionType auf „Browse“ umgestellt werden, wenn Daten von PostgreSQL gelesen werden sollen. Mehr dazu kann in der Online Hilfe lesen: https://docs.microsoft.com/en-us/dynamics-nav/currenttransactiontype-function–database- Die Integration innerhalb des SQL Servers ist also relativ unflexibel. Hier benötigt man allerdings keine Programmierung mit .NET in Dynamics NAV. Es reicht die Erstellung einer View in der NAV Datenbank, das Verknüpfen der View per LinkedObject in NAV und das Umstellen des Transaction Type in NAV. Zugriff auf die PostgreSQL Datenbank per Service Tier Für den Zugriff auf die PostgreSQL Datenbank benötigen .NET Variablen. Das sind die folgenden: <img loading="lazy" decoding="async" class="alignnone wp-image-746 size-full" src="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_NAVFunktion2.jpg" alt="" width="1221" height="147" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_NAVFunktion2.jpg 1221w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_NAVFunktion2-300x36.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_NAVFunktion2-1024x123.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_NAVFunktion2-768x92.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_NAVFunktion2-665x80.jpg 665w" sizes="auto, (max-width: 1221px) 100vw, 1221px" /> Als Text: ODBCConnection – DotNet – System.Data.Odbc.OdbcConnection.’System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′ ODBCCommand – DotNet – System.Data.Odbc.OdbcCommand.’System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′ ODBCDataReader – DotNet – System.Data.Odbc.OdbcDataReader.’System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′ Folgende Hinweise: RunOnClient sollte auf „No“ stehen. Die Verbindung zur PostgreSQL Datenbank sollte nur von der Service Tier ausgeführt werden. Baut ein Fehlerhandling ein, falls der PostgreSQL Server mal nicht erreichbar ist (TryFunction) <img loading="lazy" decoding="async" class="alignnone wp-image-748 size-full" src="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_NAVFunktion4.jpg" alt="" width="923" height="147" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_NAVFunktion4.jpg 923w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_NAVFunktion4-300x48.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_NAVFunktion4-768x122.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_NAVFunktion4-665x106.jpg 665w" sizes="auto, (max-width: 923px) 100vw, 923px" /> So könnte die Funktion zum Holen von Daten dann aussehen. Die Variable QueryText ist eine Text Variable und beinhaltet das SELECT Statement. Was ihr hier braucht hängt stark von euren Anforderungen ab. Ihr könnt eure SELECT Abfrage aber auch vorher in pgAdmin testen und dann in NAV übernehmen. Denkt daran bei großen Tabellen eure Abfrage mit einer WHERE Klausel korrekt einzuschränken. Hier bieten sich unterschiedliche Konzepte an: Nur neue Daten lesen, die beispielsweise seit dem letzten Lesevorgang aktualisiert worden sind. In diesem Fall benötigt ihr ein Feld „updated_at“ welches ohne Zeitzonen das Datum und die Uhrzeit der letzten Änderung speichert. Die Uhrzeit sollte in einem solchen Fall 6 Nachkommastellen pro Sekunde vorweisen. Nur neue Daten lesen, die beispielsweise eine neue EntryNo vorweisen. In diesem Fall dürften Daten in der PostgreSQL Datenbank nicht modifiziert werden. Jeder Änderung sollte einen neuen Eintrag generieren. Es gibt auch andere Varianten, aber ihr solltet diese Thematik in jeden Fall berücksichtigen. Wurde die Funktion korrekt ausgeführt, dann könnt ihr mit „IF ODBCDataReader.HasRows THEN“ prüfen, ob ihr Daten für eure Abfrage erhalten habt. Falls das nicht der Fall ist, könnt ihr damit die Durchführung von unnötigen Code vermeiden und die Codeausführung stoppen. <img loading="lazy" decoding="async" class="alignnone wp-image-750 size-full" src="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_NAVFunktion6.jpg" alt="" width="687" height="55" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_NAVFunktion6.jpg 687w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_NAVFunktion6-300x24.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_NAVFunktion6-665x53.jpg 665w" sizes="auto, (max-width: 687px) 100vw, 687px" /> Mit dem Befehl „WHILE ODBCDataReader.Read DO BEGIN“ könnt ihr durch jeden Eintrag eures Ergebnisses durchgehen. Die Schleife arbeitet die Daten in der korrekten Reihenfolge ab. Diese kann in dem SELECT Statement auch mit „ORDER BY“ beeinflusst werden. <img loading="lazy" decoding="async" class="alignnone wp-image-749 size-full" src="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_NAVFunktion5.jpg" alt="" width="962" height="298" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_NAVFunktion5.jpg 962w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_NAVFunktion5-300x93.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_NAVFunktion5-768x238.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_NAVFunktion5-665x206.jpg 665w" sizes="auto, (max-width: 962px) 100vw, 962px" /> Zusätzlich gibt es dann diverse Befehle um die einzelnen Spalten korrekt zu lesen: ODBCDataReader.IsDBNull(1) – prüft ob das angegebene Feld einen Wert enthält. Ihr könnt es beispielsweise überspringen, wenn es NULL ist.//Der Parameter ist die Feldnummer innerhalb der Query (0 ist das erste Feld / 1 ist das zweite Feld / 2 ist das dritte Feld / …) ODBCDataReader.GetInt32(0) – gibt den Wert als integer zurück – für NAV integer Felder geeignet ODBCDataReader.GetString(2) – gibt den Wert als String zurück – für NAV text Felder geeignet ODBCDataReader.GetBoolean(4) – gibt den Wert als boolean zurück – für NAV boolean Felder geeignet – solltet ihr hier Probleme beim Lesen der Daten bekommen, dann prüft den ODBC Treiber (System DNS) und versucht auch das Boolean Feld mit dem Befehl „COALESCE(Feld,FALSE)“ im SELECT statement zu lesen. Damit wird Null in False umgewandelt. Bei decimal Feldern muss ggf wie folgt vorgegangen werden: Convert.ToDecimal(ODBCDataReader.GetValue(10)) – Convert ist System.Convert.’mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′ Am Ende des Lesevorgangs sollte die Verbindung ordnungsgemäß geschlossen werden: ODBCConnection.Close; Ich hatte bei der Integration in NAV immer ausfüllende Leerzeichen erhalten. Anstatt „Gustav“ stand beispielsweise „Gustav “ im Namen. Diese Leerzeichen habe ich per Funktion abgeschnitten: <img loading="lazy" decoding="async" class="alignnone wp-image-751 size-full" src="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_NAVFunktionRTRIM.jpg" alt="" width="429" height="74" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_NAVFunktionRTRIM.jpg 429w, https://robert-dynamicsnav.de/wp-content/uploads/2020/07/PostgreSQL_NAVFunktionRTRIM-300x52.jpg 300w" sizes="auto, (max-width: 429px) 100vw, 429px" /> Ich halte die .NET Integration für sehr flexibel und einfach erweiterbar. Ein Wechsel des TransactionsType ist hier nicht notwendig. Die .NET Variante wird vermutlich auch noch sehr lange nutzbar sein, sofern man die Service Tier selber betreibt. In der Microsoft Cloud ohne Zugriff auf die Server sollte man sich eher mit der REST api in AL befassen und die Daten per Web Service austauschen. Wer allerdings noch länger plant OnPremise auf einem lokalen oder einem eigenen Cloud Server zu nutzen, kann die .NET Integration mit Ausführung auf dem Server noch eine ganze Weile nutzen. Dies sollte problemlos mit C/AL oder AL funktionieren. Ich hoffe das dieser Blog beim Einstieg in dieses Thema hilft. Viel Spaß. The post Dynamics NAV / Business Central mit einer PostgreSQL Datenbank verbinden first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
FILTERGROUP(-1) – Cross Column Search in Dynamics NAV / BC
Hallo zusammen, in Gesprächen mit Kollegen und Freunden im Dynamics NAV / Business Central Bereich stelle ich immer wieder fest, dass viele noch nie etwas von FILTERGROUP(-1) gehört haben. Dabei ist das sogar auf der Microsoft Online Dokumentation beschrieben (FILTERGROUP Function (Record)). Schauen wir uns die Dokumentation einmal an: Number: -1 Name: Cross-column Description: Used… Weiterlesen » The post FILTERGROUP(-1) – Cross Column Search in Dynamics NAV / BC first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Hallo zusammen, in Gesprächen mit Kollegen und Freunden im Dynamics NAV / Business Central Bereich stelle ich immer wieder fest, dass viele noch nie etwas von FILTERGROUP(-1) gehört haben. Dabei ist das sogar auf der Microsoft Online Dokumentation beschrieben (FILTERGROUP Function (Record)). Schauen wir uns die Dokumentation einmal an: Number: -1 Name: Cross-column Description: Used to support the cross-column search. Dabei werden die Dynamics NAV Experten sicherlich schon wissen worum es sich hier handelt. Mit „Cross-column“ kann über mehrere Felder gleichzeitig gesucht werden. Ich erkläre das gerne an einem Beispiel. Stellen wir uns vor, dass wir in der Kontakttabelle nach dem Suchwort „GmbH“ suchen wollen. Dabei stellt sich die Herausforderung, dass manche Kontakte einen langen Namen haben und „GmbH“ nicht im Feld „Name“, sondern im Feld „Name 2“ steht. Kontakte mit „GmbH“ im Feld „Name“: <img loading="lazy" decoding="async" class="alignnone wp-image-707 size-full" src="https://robert-dynamicsnav.de/wp-content/uploads/2020/03/KontaktListe_Name.jpg" alt="" width="417" height="310" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2020/03/KontaktListe_Name.jpg 417w, https://robert-dynamicsnav.de/wp-content/uploads/2020/03/KontaktListe_Name-300x223.jpg 300w" sizes="auto, (max-width: 417px) 100vw, 417px" /> Kontakte mit „GmbH“ im Feld „Name 2“: <img loading="lazy" decoding="async" class="alignnone size-full wp-image-708" src="https://robert-dynamicsnav.de/wp-content/uploads/2020/03/KontaktListe_Name2.jpg" alt="" width="610" height="410" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2020/03/KontaktListe_Name2.jpg 610w, https://robert-dynamicsnav.de/wp-content/uploads/2020/03/KontaktListe_Name2-300x202.jpg 300w" sizes="auto, (max-width: 610px) 100vw, 610px" /> Wie lösen wir dieses Problem? Dabei wird oft zur der Lösung gegriffen, die entsprechende Tabelle zwei Mal zu durchsuchen: In diesem Beispiel rufen wir eine Funktion „GetNoOfContactsWithSearchTerm“ auf und übergeben ‚GmbH‘ als Suchbegriff. Wir ermitteln die Anzahl der Kontakte, die diesem Filterkriterium entsprechen, indem wir auf das Feld „Name“ filtern und die Anzahl der Datensätze in der Variable „NoOfRecords“ speichern. Wir wiederholen die Abfrage mit unserem Suchbegriff, indem wir den gleichen Filter auf das Feld „Name 2“ setzen. <img loading="lazy" decoding="async" class="alignnone wp-image-709 size-full" src="https://robert-dynamicsnav.de/wp-content/uploads/2020/03/KontakteHolenMitGmbH.jpg" alt="" width="787" height="366" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2020/03/KontakteHolenMitGmbH.jpg 787w, https://robert-dynamicsnav.de/wp-content/uploads/2020/03/KontakteHolenMitGmbH-300x140.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2020/03/KontakteHolenMitGmbH-768x357.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2020/03/KontakteHolenMitGmbH-665x309.jpg 665w" sizes="auto, (max-width: 787px) 100vw, 787px" /> Das Ergebnis geben wir in einer Nachricht aus. <img loading="lazy" decoding="async" class="alignnone wp-image-710 size-full" src="https://robert-dynamicsnav.de/wp-content/uploads/2020/03/KontakteHolenMitGmbHMessage.jpg" alt="" width="202" height="124" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2020/03/KontakteHolenMitGmbHMessage.jpg 202w, https://robert-dynamicsnav.de/wp-content/uploads/2020/03/KontakteHolenMitGmbHMessage-200x124.jpg 200w" sizes="auto, (max-width: 202px) 100vw, 202px" /> Wir haben also 6 Kontakte, die GmbH im Feld „Name“ oder „Name 2“ vorweisen können. Das ist natürlich nur ein Beispiel, aber wie könnte diese Problem besser gelöst werden? Wie wäre es mit FILTERGROUP(-1): <img loading="lazy" decoding="async" class="alignnone wp-image-713 size-full" src="https://robert-dynamicsnav.de/wp-content/uploads/2020/03/KontakteHolenMitGmbHFILTERGROUP1.jpg" alt="" width="816" height="520" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2020/03/KontakteHolenMitGmbHFILTERGROUP1.jpg 816w, https://robert-dynamicsnav.de/wp-content/uploads/2020/03/KontakteHolenMitGmbHFILTERGROUP1-300x191.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2020/03/KontakteHolenMitGmbHFILTERGROUP1-768x489.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2020/03/KontakteHolenMitGmbHFILTERGROUP1-665x424.jpg 665w" sizes="auto, (max-width: 816px) 100vw, 816px" /> Das Ergebnis ist wie im Beispiel vorher: <img loading="lazy" decoding="async" class="alignnone wp-image-710 size-full" src="https://robert-dynamicsnav.de/wp-content/uploads/2020/03/KontakteHolenMitGmbHMessage.jpg" alt="" width="202" height="124" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2020/03/KontakteHolenMitGmbHMessage.jpg 202w, https://robert-dynamicsnav.de/wp-content/uploads/2020/03/KontakteHolenMitGmbHMessage-200x124.jpg 200w" sizes="auto, (max-width: 202px) 100vw, 202px" /> FILTERGROUP(-1) bietet uns die Möglichkeit Filter in Dynamics NAV / Business Central mit ODER zu verknüpfen. Ohne FILTERGROUP(-1) werden alle Filter mit UND verbunden. Schlußfolgern können wir daraus, dass wir mit FILTERGROUP(-1) Daten innerhalb einer SQL Abfrage ermitteln können und über mehrere Spalten gleichzeitig suchen können. Natürlich sollte das gut bedacht sein und für den entsprechenden Fall überprüft werden. Ab einer gewissen Datenmenge und ohne entsprechende Indexe muss die Abfrage nicht unbedingt schneller sein. Anwendung könnte FILTERGROUP(-1) beispielsweise in einer Entwicklung finden, die alle oder bestimmte Felder einer Stammdatentabelle nach einem Suchbegriff durchsucht. Das wäre in Verbindung mit FIELDREF möglich. Wir könnten daher mehrere Felder generisch nach einem Suchbegriff durchsuchen und dies dem Benutzer anzeigen. Dies ist nur eine der möglichen Anwendungsbereiche. Bei Prüfungen, ob eins von vielen Felder gefüllt sind, könnte sich der Cross-column search auch anbieten. Ich bin mir sicher, dass die meisten Entwickler schon Ideen haben, FILTERGROUP für ihre Anforderung zu verwenden. Viel Spaß. The post FILTERGROUP(-1) – Cross Column Search in Dynamics NAV / BC first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
RDLC für NAV Entwickler #6 – RDLC Belegdesign – Übertrag
Hallo zusammen, heute möchte ich ein erklären, wie ich den Übertrag in RDLC löse. Wer sich vorher nochmal einlesen möchte, kann sich hier die vorherigen Beiträge ansehen: RDLC für NAV Entwickler #1 – Allgemeine Informationen & das Dataset RDLC für NAV Entwickler #2 – Grundlagen des Layouts – Teil 1 „Der Kopf“ RDLC für NAV… Weiterlesen » The post RDLC für NAV Entwickler #6 – RDLC Belegdesign – Übertrag first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Hallo zusammen, heute möchte ich ein erklären, wie ich den Übertrag in RDLC löse. Wer sich vorher nochmal einlesen möchte, kann sich hier die vorherigen Beiträge ansehen: RDLC für NAV Entwickler #1 – Allgemeine Informationen & das Dataset RDLC für NAV Entwickler #2 – Grundlagen des Layouts – Teil 1 „Der Kopf“ RDLC für NAV Entwickler #3 – Grundlagen des Layouts – Teil 2 „Der Textkörper“ RDLC für NAV Entwickler #4 – Kopieren von Berichten / Layouts RDLC für NAV Entwickler #5 – RDLC Belegdesign – Grundlagen & unterschiedliche Kopfgröße Folgende Restriktionen sollten vorher bekannt sein: Der Übertrag kann nur in der Kopfzeile und/oder in der Fußzeile angezeigt werden. Der Übertrag kann sich nur auf eine Textbox beziehen. Werden mehrere Layoutzeilen in einer Verkaufsrechnung benötigt (beispielsweise eine Zeile für Artikel und eine Zeile für Sachkonten), wird ein Workaround benötigt. Wie das gelöst werden kann, wird hier nicht detailliert behandelt. Evtl. erkläre ich das am Beispiel der Mahnung in einem anderen Beitrag (kleiner Tipp: Arbeitet nicht mit zwei Zeilen, sondern mit einer Zeile. Verbindet alle Textboxen (außer dem Zeilenbetrag) miteinander und klickt dann Rechtsklick „Einfügen“ -> „Rechteck“. In dem Rechteck bildet ihr dann mit zwei separaten Rechtecken und entsprechenden Sichtbarkeiten die unterschiedlichen Layouts für Artikel / Sachkonten ab. Das hat den Vorteil, dass ihr dann nur eine Textbox für den Zeilenbetrag habt und über diesen summieren könnt. In diesem Fall funktioniert auch die in diesem Beitrag beschriebene Logik.). Der Übertrag muss manuell mit eigenem Programmcode gebildet werden. Es gibt keine integrierte Funktion in Visual Studio, die uns eine Übertragsfunktion ermöglicht (bei der Seitennummer gibt es beispielsweise die Eigenschaft „ResetPageNo“ an der Gruppe). Damit ihr nachvollziehen könnt, was genau ändere, nutze ich als Basis benutze den Beispielbeleg aus meinem letzten Beitrag zum Thema RDLC: 160312_RobertsVKRechnung Diesen Bericht habe ich in eine Dynamics NAV 2018 Datenbank eingespielt und dann in Visual Studio 2017 (Ansicht + Layout) geöffnet. Dafür benötigt ihr die Visual Studio 2017 Professional Version oder Visual Studio 2017 Community Edition (https://www.visualstudio.com/de/downloads/). Bitte informiert euch über die Lizenzbedingung der Community Edition, bevor ihr diese benutzt. Zusätzlich benötigt ihr die Erweiterungen „Microsoft Rdlc Report Designer for Visual Studio“ (https://marketplace.visualstudio.com/items?itemName=ProBITools.MicrosoftRdlcReportDesignerforVisualStudio-18001). Nach einen Neustart des Computers, solltet ihr RDLC Belege wieder ordnungsgemäß mit Visual Studio öffnen können. Ohne die Erweiterung kann Visual Studio das Layout nicht laden und ihr bekommt nur eine XML angezeigt. So sieht das Layout aus, mit dem wir starten: <img loading="lazy" decoding="async" class="alignnone wp-image-578 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_1_Verkaufsrechnung.jpg" alt="" width="669" height="790" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_1_Verkaufsrechnung.jpg 669w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_1_Verkaufsrechnung-254x300.jpg 254w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_1_Verkaufsrechnung-665x785.jpg 665w" sizes="auto, (max-width: 669px) 100vw, 669px" /> Bevor wir beginnen, sollten wir zuerst zusammenfassen, welche Anforderungen wir erfüllen müssen. Der Übertrag darf im Kopf nur gedruckt werden, wenn auf der vorherigen Seite bereits Zeilen gedruckt wurden und die Gesamtsumme auf der vorherigen Seite noch nicht gedruckt wurde. Der Übertrag darf im Fuß nur zu sehen sein, wenn die Gesamtsumme nicht auf der aktuellen Seite gedruckt wurde. Beim Stapeldruck mehrerer Verkaufsrechnungen muss der Übertrag zurückgesetzt werden. Auf die Summenlogik gehe ich hier nicht weiter ein. Falls das von Interesse ist, kann das in den Standardbelegen nachgeschaut werden. Für unser Beispiel und zur Erläuterung füge ich eine einfache Summenzeile in unserem Layout ein. Das ist keine Empfehlung, sondern ausschließlich exemplarisch gedacht. Somit sollte die Positionierung von Elementen klar erkennbar und auch auf andere Belege anwendbar sein. In der Textbox außerhalb der Gruppe und unterhalb des Zeilenbetrags ergänze ich den Ausdruck „=Sum(Fields!LineAmount_Line.Value)“. Die Formatierung ändere ich auf Fett und ergänze in der Textbox links daneben den Text „Summe“. Zusätzlich entferne ich den leeren Platzhalter. Summenzeile hinzufügen: <img loading="lazy" decoding="async" class="alignnone wp-image-579 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_2_Summenzeile1.jpg" alt="" width="655" height="281" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_2_Summenzeile1.jpg 655w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_2_Summenzeile1-300x129.jpg 300w" sizes="auto, (max-width: 655px) 100vw, 655px" /> Ausdruck hinterlegen: <img loading="lazy" decoding="async" class="alignnone wp-image-580 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_3_Summenzeile2.jpg" alt="" width="966" height="550" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_3_Summenzeile2.jpg 966w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_3_Summenzeile2-300x171.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_3_Summenzeile2-768x437.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_3_Summenzeile2-665x379.jpg 665w" sizes="auto, (max-width: 966px) 100vw, 966px" /> Platzhalter löschen und Caption „Summe“ ergänzen: <img loading="lazy" decoding="async" class="alignnone wp-image-581 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_4_Summenzeile3.jpg" alt="" width="695" height="270" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_4_Summenzeile3.jpg 695w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_4_Summenzeile3-300x117.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_4_Summenzeile3-665x258.jpg 665w" sizes="auto, (max-width: 695px) 100vw, 695px" /> Zum Druck von Textzeilen ergänze ich die Funktion „BlankZero“ in den Feldern Menge, Verkaufspreis und Betrag: <img loading="lazy" decoding="async" class="alignnone wp-image-585 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_4_Summenzeile4.jpg" alt="" width="1003" height="273" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_4_Summenzeile4.jpg 1003w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_4_Summenzeile4-300x82.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_4_Summenzeile4-768x209.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_4_Summenzeile4-665x181.jpg 665w" sizes="auto, (max-width: 1003px) 100vw, 1003px" /> Im Feld „Betrag“ darf dies nicht gemacht werden. Mit der Funktion „BlankZero“ wird aus einer Null ein Leerzeichen. Ein Leerzeichen kann nicht summiert werden, was aber dringend für den Übertrag notwendig ist. Daher ändere ich die Schriftfarbe auf weiß, wenn der Betrag null ist (Ausdruck: =iif(Fields!LineAmount_Line.Value = 0, „White“, „Black“)). Im heutigen Beispiel buche ich mir eine Verkaufsrechnungen mit genug Zeilen in meine Demodatenbank. Im Druck sieht das nun so aus: Seite 1: <img loading="lazy" decoding="async" class="alignnone wp-image-583 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_5_Vorschau1.jpg" alt="" width="811" height="803" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_5_Vorschau1.jpg 811w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_5_Vorschau1-150x150.jpg 150w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_5_Vorschau1-300x297.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_5_Vorschau1-768x760.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_5_Vorschau1-665x658.jpg 665w" sizes="auto, (max-width: 811px) 100vw, 811px" /> Seite 2: <img loading="lazy" decoding="async" class="alignnone wp-image-584 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_6_Vorschau2.jpg" alt="" width="832" height="370" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_6_Vorschau2.jpg 832w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_6_Vorschau2-300x133.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_6_Vorschau2-768x342.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_6_Vorschau2-665x296.jpg 665w" sizes="auto, (max-width: 832px) 100vw, 832px" /> Nun ergänzen wir die Summenlogik. Dafür arbeite ich mit VB Code. Diesen können wir öffnen, indem wir die Berichtseigenschaften öffnen. <img loading="lazy" decoding="async" class="alignnone wp-image-599 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_7_Berichtseigenschaften.jpg" alt="" width="826" height="156" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_7_Berichtseigenschaften.jpg 826w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_7_Berichtseigenschaften-300x57.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_7_Berichtseigenschaften-768x145.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_7_Berichtseigenschaften-665x126.jpg 665w" sizes="auto, (max-width: 826px) 100vw, 826px" /> Anschließend können wir folgenden Code ergänzen: Shared RunningTotals As New System.Collections.Hashtable Shared LastPage as boolean Shared TransHeaderValue as boolean Public Function StartPage() as boolean LastPage = false return LastPage End Function Public Function SetLastPage() as boolean LastPage = true return LastPage End Function Public Function GetLastPage() as boolean return LastPage End Function Public Function GetRunningTotal(ByVal CurrentPageNumber) Return IIF(CurrentPageNumber > 0, RunningTotals(CurrentPageNumber), 0) End Function Public Function SetRunningTotal(ByVal CurrentPageTotal, ByVal CurrentPageNumber) RunningTotals(CurrentPageNumber) = CurrentPageTotal + GetRunningTotal(CurrentPageNumber - 1) Return RunningTotals(CurrentPageNumber) End Function Public Function SetTransHeader(ByVal Value) as boolean TransHeaderValue = Value Return TransHeaderValue End Function Public Function GetTransHeader() as boolean Return TransHeaderValue End Function <img loading="lazy" decoding="async" class="alignnone wp-image-600 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_8_Berichtscode.jpg" alt="" width="750" height="557" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_8_Berichtscode.jpg 750w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_8_Berichtscode-300x223.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_8_Berichtscode-665x494.jpg 665w" sizes="auto, (max-width: 750px) 100vw, 750px" /> Damit sind die Vorbereitungen abgeschlossen. Hier eine kurze Erläuterung, wozu die Funktionen dienen: StartPage: Setzt die boolsche Variable „LastPage“ zurück. Erforderlich, damit im Stapeldruck der Übertrag nicht auf der ersten Seite des nächsten Beleges gedruckt wird. SetLastPage: Setzt eine boolsche Variable „LastPage“. Die Funktion muss aufgerufen werden, nachdem die Summe gedruckt wurde. Die boolsche Variable gibt uns an, wie lange wir den Übertrag drucken müssen. Solange die Variable nicht True ist, drucken wir den Übertrag. GetLastPage: Ruft die Variable „LastPage“ ab. GetRunningTotal: Ruft den aktuellen Übertrag für eine spezifische Seite ab. SetRunningTotal: Setzt den Übertrag. SetTransHeader: Setzt ein Marker. Wird im Footer gesetzt (notwendig wegen Renderlogik von RDL – Zuerst wird der Textkörper aufgebaut und danach der Kopf und der Fuß angedockt). GetTransHeader: Ruft den Marker ab um zu prüfen, ob der Übertrag gedruckt werden soll oder nicht. Die Funktionen müssen nun im Layout aufgerufen werden. Beginnen wir mit der Funktion „StartPage„. Folgendes wird dafür getan: Neue Tabelle „Table_SetFirstPage“ ohne Gruppe im Rechteck „HeaderFirstPage_2“ einfügen und mit nur einer Textbox „StartPage“ erstellen. In der Textbox „Startpage“ den Ausdruck „=Code.StartPage()“ hinterlegen. Die Textbox „Startpage“ auf Hidden „True“ und die Hintergrundfarbe auf Rot (zeigt besser, dass es sich um ein rein funktionales Element handelt) setzen. <img loading="lazy" decoding="async" class="alignnone wp-image-602 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_9_StartPage.jpg" alt="" width="932" height="660" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_9_StartPage.jpg 932w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_9_StartPage-300x212.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_9_StartPage-768x544.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_9_StartPage-60x42.jpg 60w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_9_StartPage-665x471.jpg 665w" sizes="auto, (max-width: 932px) 100vw, 932px" /> Wichtig ist hierbei folgendes: Die Funktion „StartPage“ muss garantiert auf der ersten Seite ausgeführt werden. Als nächstes deklarieren wir das Ende, also ab wenn der Übertrag nicht mehr gedruckt werden soll. Das machen wir mit der Funktion „SetLastPage„. Diese platzieren wir in einer Tabelle nach der Summe. Neue Tabelle „Table_SetLastPage“ ohne Gruppe unter der Summe einfügen (innerhalb des Rechtecks „DocumentContent“) und mit nur einer Textbox „SetLastPage“ erstellen. In der Textbox „SetLastPage“ den Ausdruck „=Code.SetLastPage()“ hinterlegen. Die Textbox „Startpage“ auf Hidden „True“ und die Hintergrundfarbe auf Rot setzen. <img loading="lazy" decoding="async" class="alignnone wp-image-603 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_10_SetLastPage.jpg" alt="" width="900" height="623" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_10_SetLastPage.jpg 900w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_10_SetLastPage-300x208.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_10_SetLastPage-768x532.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_10_SetLastPage-60x42.jpg 60w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_10_SetLastPage-665x460.jpg 665w" sizes="auto, (max-width: 900px) 100vw, 900px" /> Dabei muss berücksichtigt werden, dass sich das Element immer direkt hinter der Summe befindet. Nun benötigen wir noch ein Element für die Funktion „SetTransHeader„, welches beim Rendern der Fußzeile erkennt, ob die letzte Seite des Beleges bereits gedruckt wurde oder nicht. Dieses Element wird nicht ausgeblendet. Damit gibt es nämlich vor allem in älteren Versionen Probleme. Dafür tue ich folgendes: Einfügen einer Fußzeile Einfügen einer Textbox „Transheader_Marker“ Einfügen des Ausdruckes „=Code.SetTransHeader(Code.GetLastPage())“ Setzen der Eigenschaft „CanGrow“ auf False Platzieren des Elementes in der Fußzeile oben links und verkleinern der Textbox auf Size = „1cm; 0,1cm“ <img loading="lazy" decoding="async" class="alignnone wp-image-604 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_11_TransheaderMarker.jpg" alt="" width="981" height="717" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_11_TransheaderMarker.jpg 981w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_11_TransheaderMarker-300x219.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_11_TransheaderMarker-768x561.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_11_TransheaderMarker-665x486.jpg 665w" sizes="auto, (max-width: 981px) 100vw, 981px" /> Damit sind die Vorbereitungen getroffen. Wir benötigen nun die Textboxen für den Übertrag. Beginnen wir im Fuß für die Funktion „SetRunningTotal„: Einfügen eines Rechteckes „CarryOverContentFooter“ in der Fußzeile mit der Eigenschaft „Hidden“ = „=IIF((Globals!PageNumber < Globals!TotalPages) AND NOT Code.GetLastPage(), False, True)“. Einfügen einer Textbox „CarryOverCaptionFooter“ mit dem Ausdruck „Fortsetzung“ Einfügen einer Textbox „CarryOverAmountFooter“ mit dem Ausdruck „=Code.SetRunningTotal(Sum(ReportItems!LineAmount_Line.Value), Globals!PageNumber)“ und Format „#,0.00;(#,0.00)“ <img loading="lazy" decoding="async" class="alignnone wp-image-610 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_12_ÜbertragFooter1.jpg" alt="" width="1164" height="557" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_12_ÜbertragFooter1.jpg 1164w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_12_ÜbertragFooter1-300x144.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_12_ÜbertragFooter1-768x368.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_12_ÜbertragFooter1-1024x490.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_12_ÜbertragFooter1-665x318.jpg 665w" sizes="auto, (max-width: 1164px) 100vw, 1164px" /> Nun erstellen wir im Kopf ebenfalls den Bereich für den Übertrag. Da wir zwei Rechtecke haben (eins für Seite 1 und eins für die restlichen Seiten) fügen wir den Übertrag auf dem Rechteck für Seite 2+ (HeaderSecondPage) ein. Damit stellen wir sicher, dass der Übertrag niemals auf der ersten Seite im Kopf gedruckt wird. Enthält euer Berichtslayout nur eine Seite, dann benötigt das Rechteck für den Übertrag im Kopf in der Hidden Eigenschaft auch eine Prüfung auf die Seitennummer (nur drucken, wenn Seite > 1). Einfügen eines Rechteckes „CarryOverContentHeader“ im Rechteck „HeaderSecondPage“ mit der Eigenschaft „Hidden“ = „=iif(Code.GetTransHeader() = False, False, True)“. Einfügen einer Textbox „CarryOverCaptionHeader“ mit dem Ausdruck „Fortsetzung“ Einfügen einer Textbox „CarryOverAmountHeader“ mit dem Ausdruck „=Code.GetRunningTotal(Globals!PageNumber-1)“ und Format „#,0.00;(#,0.00)“ <img loading="lazy" decoding="async" class="alignnone wp-image-611 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_13_ÜbertragHeader1.jpg" alt="" width="1433" height="510" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_13_ÜbertragHeader1.jpg 1433w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_13_ÜbertragHeader1-300x107.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_13_ÜbertragHeader1-768x273.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_13_ÜbertragHeader1-1024x364.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_13_ÜbertragHeader1-665x237.jpg 665w" sizes="auto, (max-width: 1433px) 100vw, 1433px" /> Schauen wir uns nun den Druck in der Seitenansicht an: Seite 1 <img loading="lazy" decoding="async" class="alignnone wp-image-612 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_14_Seite1.jpg" alt="" width="822" height="842" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_14_Seite1.jpg 822w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_14_Seite1-293x300.jpg 293w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_14_Seite1-768x787.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_14_Seite1-665x681.jpg 665w" sizes="auto, (max-width: 822px) 100vw, 822px" /> Seite 2 <img loading="lazy" decoding="async" class="alignnone wp-image-613 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_15_Seite2.jpg" alt="" width="826" height="375" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_15_Seite2.jpg 826w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_15_Seite2-300x136.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_15_Seite2-768x349.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_15_Seite2-658x300.jpg 658w, https://robert-dynamicsnav.de/wp-content/uploads/2018/04/RDLCLayout_15_Seite2-665x302.jpg 665w" sizes="auto, (max-width: 826px) 100vw, 826px" /> Solltet ihr mehrere Rechnungen am Stück drucken, so stellt sicher, dass die Seitennummer bei jedem Beleg zurückgesetzt wird. Sofern das sichergestellt ist, ist diese Funktion auch für den Stapeldruck geeignet. That’s it. Have fun. Abschließend möchte ich noch sagen, dass es einige Übertragsbeíspiele im Netz gibt. Darunter ist auch eine Option ohne das Element „TransferHeader_Marker“ und die entsprechenden Funktionen. Letztlich hängt es auch von der Dynamics NAV Version ab, welche Integration funktioniert. Ich kann dazu nur sagen, dass vor allem in früheren Dynamics NAV Versionen (2009-2013 R2) Probleme mit ausgeblendeten Elementen (mit der Eigenschaft Hidden = True) gab. Meiner Erfahrung nach funktioniert die oben beschriebene Variante in allen Dynamics NAV Versionen (2009 bis 2018) und daher nutze ich diese auch. Meinen angepassten Bericht findet ihr hier als ZIP (enthält TXT und FOB): 180408_RobertsRechnungÜbertrag Ich hoffe dies hilft dem ein oder anderem. The post RDLC für NAV Entwickler #6 – RDLC Belegdesign – Übertrag first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Dynamics NAV / SQL Server Performance Tipps & Tricks
Hallo zusammen, heute möchte ich meine Erfahrungen zu Dynamics NAV Performance teilen. Dabei gibt es ein paar Dinge die meist schnell eingestellt sind und für verbesserte Leistung sorgen. Performanceprobleme können in jeder Dynamics NAV Datenbank auftreten. Dabei sind auch ältere Tipps dabei. Dies soll einen grundlegenden Überblick über die Einstellungen geben, auf die ich bei… Weiterlesen » The post Dynamics NAV / SQL Server Performance Tipps & Tricks first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Hallo zusammen, heute möchte ich meine Erfahrungen zu Dynamics NAV Performance teilen. Dabei gibt es ein paar Dinge die meist schnell eingestellt sind und für verbesserte Leistung sorgen. Performanceprobleme können in jeder Dynamics NAV Datenbank auftreten. Dabei sind auch ältere Tipps dabei. Dies soll einen grundlegenden Überblick über die Einstellungen geben, auf die ich bei Installationen besonders achte. Dynamics NAV Service Tier Einstellungen Diese Werte stehen in der Datei „CustomSettings.config“ im Verzeichnis der Service Tier zur Verfügung. Sie können über die Dynamics NAV Administration oder über einen Editor direkt in der Konfigdatei geändert werden. Nach Änderung eines Wertes ist ein Neustart des Service Tier notwendig, damit die Einstellungen auch greifen. MetadataProviderCacheSize: Diese Option steht seit Dynamics NAV 2009 RTC zur Verfügung und hat einen Standardwert von 150. Hiermit wird angegeben, wie viele Objekte in Cache gespeichert werden. Dieser Wert sollte so gewählt werden, dass alle genutzten Objekte auch im Cache gespeichert werden. Wird der Wert auf 5000 oder höher gesetzt, wird jedes Objekt auch im Cache gespeichert. Es ist zu empfehlen den Wert entsprechend zu erhöhen. <img loading="lazy" decoding="async" class="alignnone wp-image-530 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_Performance_MetadataProviderCacheSize.jpg" alt="" width="449" height="97" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_Performance_MetadataProviderCacheSize.jpg 449w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_Performance_MetadataProviderCacheSize-300x65.jpg 300w" sizes="auto, (max-width: 449px) 100vw, 449px" /> MaxConcurrentCalls: Dieser Wert bestimmt, wie viele gleichzeitige Anfragen von den Clients abgeschickt werden können. Dieser Wert kann ebenfalls erhöht werden. Als Richtwert nehme ich die maximal gleichzeitig angemeldete Benutzeranzahl auf der Service Tier x 2. Arbeiten also max. 20 Benutzer auf der Service Tier, dann verändere ich den Wert auch nicht. Der Wert steht ab NAV 2009 RTC zur Verfügung. <img loading="lazy" decoding="async" class="alignnone wp-image-529 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_Performance_MaxConcurrentCalls.jpg" alt="" width="369" height="96" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_Performance_MaxConcurrentCalls.jpg 369w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_Performance_MaxConcurrentCalls-300x78.jpg 300w" sizes="auto, (max-width: 369px) 100vw, 369px" /> DisableSmartSQL: Ab NAV 2015 steht die Eigenschaft „DisableSmartSQL“ zur Verfügung. Diese Option ist standardmäßig nicht aktiviert. Das sollte auch nicht verändert werden. Wenn die Service Tier mit SmartSQL arbeitet, werden Abfragen gebündelt statt einzeln an den SQL Server übertragen. Beispiel: Wird die Kontaktliste geöffnet und dort ist eine Factbox mit Flowfeldern enthalten, welche Daten aus den Aktivitätenprotokollposten anzeigt, dann schickt NAV ein kombiniertes SELECT für die Kontakttabelle und die Aktivitätenprotokollposten ab. Ist SmartSQL deaktiviert, dann werden die Information einzeln abgefragt. Dieser Wert sollte dann temporär aktiviert werden, wenn Performanceproblemen auf die Schliche kommen möchte. Ab Dynamics NAV 2017 meldet die Service Tier in der Ereignisanzeige nämlich auch langsame Skripte. Das sieht beispielsweise so aus: <img loading="lazy" decoding="async" class="alignnone wp-image-528 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_LongRunningSQLStatement.jpg" alt="" width="922" height="328" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_LongRunningSQLStatement.jpg 922w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_LongRunningSQLStatement-300x107.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_LongRunningSQLStatement-768x273.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_LongRunningSQLStatement-665x237.jpg 665w" sizes="auto, (max-width: 922px) 100vw, 922px" /> In diesen Fall dauert die Abfrage auf ein Individualfeld „Work Description“ im Verkaufskopf länger als 10 Sekunden. Dabei werden zwar die Filter für die Felder „Document Type“ und „No.“ nicht angezeigt, aber diese Meldungen in der Ereignisanzeige können Indikatoren auf Probleme in Zusammenhang mit dem Feld sein. Es besteht die Möglichkeit, dass es kein Schlüssel für das Feld „Work Description“ gibt. Es gibt aber auch deutlich komplexere Meldung, wie diese hier: <img loading="lazy" decoding="async" class="alignnone wp-image-531 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_LongRunningSQLStatementWithSmartSQL.jpg" alt="" width="1365" height="507" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_LongRunningSQLStatementWithSmartSQL.jpg 1365w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_LongRunningSQLStatementWithSmartSQL-300x111.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_LongRunningSQLStatementWithSmartSQL-768x285.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_LongRunningSQLStatementWithSmartSQL-1024x380.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_LongRunningSQLStatementWithSmartSQL-665x247.jpg 665w" sizes="auto, (max-width: 1365px) 100vw, 1365px" /> In diesem Fall kann es helfen „DisableSmartSQL“ zu aktivieren. Damit kann der langsame Teil besser identifiziert werden, da kein kombiniertes SQL Statement mehr übertragen wird. Sind die Probleme gefunden, sollte „DisableSmartSQL“ wieder deaktiviert werden. Compile and Load Business Application: Die Service Tier speichert Teile der Anwendung bereits im Arbeitsspeicher und verkürzt somit Antwortzeiten nachdem die Service Tier neugestartet wurde. Daher ist meine Empfehlung diesen Option zu aktivieren bzw. aktiviert zu lassen. Diese Option steht ab Dynamics NAV 2016 zur Verfügung. Details dazu auch hier zu finden: https://msdn.microsoft.com/de-de/library/hh174007(v=nav.90).aspx Data Cache Size: Dieser Wert gibt an, wie viel Arbeitsspeicher eine Service Tier für das Cachen von Daten verbrauchen darf. Dabei sind die Werte wie folgt aufgeteilt: 9 -> 2 hoch 9 = 512 MB 10 -> 2 hoch 10 = 1.024 MB 11 -> 2 hoch 11 = 2.048 MB 12 -> 2 hoch 12 = 4.096 MB 13 -> 2 hoch 13 = 8.192 MB 14 -> 2 hoch 14 = 16.384 MB 15 -> 2 hoch 15 = 32.768 MB Diese Eigenschaft wird oft angepriesen, allerdings habe ich hierdurch kaum Performanceverbesserungen gespürt. Diese Einstellung kann man also im Hinterkopf behalten, aber es sollte nicht zu viel erwartet werden. SQL Server Einstellung Am meisten kann man jedoch direkt am SQL Server optimieren. Dafür gibt es folgende Einstellungen Gruppenrichtlinien: In den Gruppenrichtlinien am SQL Server sollten dir Rechte für den Dienstbenutzer des SQL Servers verändert werden. Zu empfehlen sind die folgenden Rechte: „Durchführen von Volumenwartungsaufgaben“ (mehr dazu hier: https://support.microsoft.com/de-de/help/2964518/recommended-updates-and-configuration-options-for-sql-server-2012-and) „Sperren von Seiten im Speicher“ (mehr dazu hier: https://docs.microsoft.com/de-de/sql/database-engine/configure-windows/enable-the-lock-pages-in-memory-option-windows). Die Gruppenrichtlinien erreicht man wie folgt. – Ausführen: gpedit.msc / Öffnen von „Computerkonfiguration“ -> „Windows-Einstellungen“ -> „Sicherheitseinstellungen“ -> „Lokale Richtlinien“ -> „Zuweisen von Benuterrechten“ <img loading="lazy" decoding="async" class="alignnone wp-image-534 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_Gruppenrichtlinien1.jpg" alt="" width="478" height="277" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_Gruppenrichtlinien1.jpg 478w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_Gruppenrichtlinien1-300x174.jpg 300w" sizes="auto, (max-width: 478px) 100vw, 478px" /> <img loading="lazy" decoding="async" class="alignnone wp-image-535 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_Gruppenrichtlinien2.jpg" alt="" width="925" height="679" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_Gruppenrichtlinien2.jpg 925w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_Gruppenrichtlinien2-300x220.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_Gruppenrichtlinien2-768x564.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_Gruppenrichtlinien2-665x488.jpg 665w" sizes="auto, (max-width: 925px) 100vw, 925px" /> Arbeitsspeicher: Arbeitsspeicher ist eines der wichtigsten Ressourcen für den SQL Server. Sind Daten erst mal im Cache, dann werden diese auch schnell abgerufen. Dabei achte ich auf zwei Faustregeln. – Festlegen von maximalen Arbeitsspeicher des SQL Servers: Das vermeidet, dass der SQL Server zu viel Arbeitsspeicher verwendet, sodass der SQL Server mit 99 % RAM-Auslastung den Server lahm legt. Es ist darauf zu achten, dass auch dem System etwas Arbeitsspeicher zur Verfügung steht. Konstruiertes Beispiel: 16 GB stehen auf dem SQL Server zur Verfügung. Es läuft der SQL Server und ein Echtsystem, Testsystem, sowie ein NAS auf der Maschine. Hier habe ich den SQL Server auf 12 GB gesetzt. Prüft hier einfach, wie viel Kapazitäten ihr habt und justiert das Limit entsprechend (siehe https://technet.microsoft.com/de-de/library/ms191144(v=sql.105).aspx). <img loading="lazy" decoding="async" class="alignnone wp-image-536 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_MaxArbeitsspeicherSQLServer.jpg" alt="" width="762" height="320" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_MaxArbeitsspeicherSQLServer.jpg 762w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_MaxArbeitsspeicherSQLServer-300x126.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_MaxArbeitsspeicherSQLServer-665x279.jpg 665w" sizes="auto, (max-width: 762px) 100vw, 762px" /> – Erhöhung des Arbeitsspeichers: Es kann zu starken Verbesserungen kommen, wenn der Maximalwert vom SQL Server voll genutzt wird (kann per Ressourcenmonitor geprüft werden) und bei gleicher Aktivität Dynamics NAV mal langsam und mal schnell ist. Das kann dann dafür sprechen, das Daten mal im Cache sind und mal nicht. Nach Erhöhung des Arbeitsspeichers sollte ebenfalls das maximale Limit im SQL Server erhöht werden. Indexanalyse: Mit der Indexanalyse können erhebliche Verbesserungen der Leistung herbeigeführt werden. Dafür gibt es grundsätzlich zwei Skripte: -> Skript zur Ermittlung fehlender Schlüssel SELECT CONVERT (DECIMAL (28,1), migs.avg_total_user_cost * migs.avg_user_impact * (migs.user_seeks + migs.user_scans) ) AS improvement_measure, mid.statement AS table_name, mid.equality_columns, mid.inequality_columns, mid.included_columns, migs.avg_user_impact, migs.unique_compiles, migs.user_seeks, migs.user_scans, migs.last_user_seek, migs.last_user_scan, 'CREATE INDEX [missing_index_' + CONVERT(VARCHAR, mig.index_group_handle) + '_' + CONVERT(VARCHAR, mid.index_handle) + '_' + LEFT(PARSENAME(mid.statement, 1), 32) + ']' + ' ON ' + mid.statement + ' (' + ISNULL(mid.equality_columns, '') + CASE WHEN mid.equality_columns IS NOT NULL AND mid.inequality_columns IS NOT NULL THEN ',' ELSE '' END + ISNULL(mid.inequality_columns, '') + ')' + ISNULL(' INCLUDE (' + mid.included_columns + ')', '') AS create_index_statement FROM sys.dm_db_missing_index_groups mig INNER JOIN sys.dm_db_missing_index_group_stats migs ON migs.group_handle = mig.index_group_handle INNER JOIN sys.dm_db_missing_index_details mid ON mig.index_handle = mid.index_handle ORDER BY migs.avg_total_user_cost * migs.avg_user_impact * (migs.user_seeks + migs.user_scans) DESC; Als Ergebnis bekommt man eine Tabelle mit der Auswertung der Statistiken des SQL Servers. Dabei soll die Spalte „improvement_measure“ eine grobe Wertung des Einflusses darstellen. Umso höher der Wert umso wahrscheinlicher, dass nach der Anlage des fehlenden Index das System in diesem Bereich schneller ist. Zusätzlich wird die betroffene Tabelle und die betroffenen Felder angezeigt. Die Spalte user_seeks ist für mich besonders wichtig. Hieran kann ich erkennen, wie oft der SQL Server den Index gebraucht hätte. Einträge mit höheren Werte werden häufiger gebraucht und haben damit auch einen höheren Einfluss. Wenn die Datenbank schon zwei Jahre läuft und es 5 Seeks für einen Index gibt, dann sind diese in der Regel nicht sehr bedeutsam. Da gibt es zwar auch Ausnahmen, auf die ich jetzt nicht weiter eingehe. In der Spalte „last_user_seek“ kann man auch sehen, wann der Index das letzte mal benötigt wurde. <img loading="lazy" decoding="async" class="alignnone wp-image-563 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_SQL_MissingIndex.jpg" alt="" width="1091" height="164" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_SQL_MissingIndex.jpg 1091w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_SQL_MissingIndex-300x45.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_SQL_MissingIndex-768x115.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_SQL_MissingIndex-1024x154.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_SQL_MissingIndex-665x100.jpg 665w" sizes="auto, (max-width: 1091px) 100vw, 1091px" /> In diesem Beispiel sieht man, dass es einen Eintrag mit ca. 28.000 user_seeks gibt. Diesen Index schaue ich mir dann näher an. Welche Tabelle ist betroffen, welche Felder sind betroffen, welcher Prozess ist davon eventuell betroffen? In diesem Fall ist Bemerkungstabelle betroffen. Als Lösung gibt es nun zwei Möglichkeiten: Index (Schlüssel) in Dynamics NAV anlegen (falls möglich) – Dies gilt dann für alle Mandanten – einige Schlüssel können nicht in NAV angelegt werden Index über den SQL Server anlegen – Dies gilt dann nur für den betroffenen Mandanten – In der Spalte „create_index_statement“ wird ein Skript vorbereitet, welches in eine neue Abfrage kopiert werden kann. Führt man diese dann aus, wird der Index nur auf dem SQL Server angelegt. Es gibt hier verschiedene Ansätze, wann man etwas wie tun sollte. Pauschal gesagt, kann man hiermit schnell fehlende Indexe anlegen und kann damit auch Performancesteigerungen erreichen. Dennoch ist eine präzise Analyse der „langsamen“ Vorgänge besser, als einfach Indexe anzulegen. Die Anlage von Indexen kann im Livebetrieb vorgenommen werden. Es ist aber zu spüren, das heißt die Performance für NAV sinkt, während der SQL Server Indexe aufbaut. Ein Tipp noch am Rande: Steht im Create Index Statement ein INCLUDE [timestamp] am Ende, dann kann das INCLUDE inkl. der folgenden Felder gelöscht werden. Das sind nämlich alle Felder der Tabelle. Es ist ratsam diese Prüfungen regelmäßig durchzuführen. Dazu sollte auch geprüft werden, ob angelegte Schlüssel überhaupt positive Effekte erwirken konnten. Dazu gibt es das folgende Skript. -> Skript zur Ermittlung, ob angelegte Indexe überhaupt verwendet werden In diesem Skript werden euch alle Indexe angezeigt, die ihr mit dem oben genannten Skript angelegt habt. Ihr könnt hier sehen, wie oft die Indexe tatsächlich genutzt wurden und wie oft der SQL Server diesen Index auch mit aufgebaut hat. Zusätzlich besteht beispielsweise mit der Spalte „tsql_DROP“ die Möglichkeit den Index wieder zu löschen (Inhalt des Feldes in eine neue Abfrage kopieren und ausführen). Das macht vor allem dann Sinn, wenn dieser nie verwendet wurde. Dann kostet der Index nur Ressourcen und sollte wieder entfernt werden. Beachtet dabei, dass wenn die Werte in den Spalten „user_seeks“, „user_scans“, „user_lookups“, „user_updates“ alle NULL sind, dass es sich hier vermutlich um einen frisch angelegten Schlüssel handelt. USE [databasename] -- change db name on demand GO SELECT object_name(sysidx.[object_id]) as [object_name], sysidx.[name] as [index_name], idxcol.key_columns, idxcol.included_columns, sysidx.filter_definition, idxusg."user_seeks", idxusg."user_scans", idxusg."user_lookups", idxusg."user_updates", 'IF NOT EXISTS (SELECT TOP 1 NULL FROM sys.indexes (NOLOCK) WHERE object_name([object_id]) = ''' + object_name(sysidx.[object_id]) + ''' AND [name] = ''' + sysidx.[name] + ''') CREATE INDEX [' + sysidx.[name] + '] ON [' + object_name(sysidx.[object_id]) + '] (' + idxcol.key_columns + ')' + CASE WHEN idxcol.included_columns is not null THEN ' INCLUDE (' + idxcol.included_columns + ')' ELSE '' END + CASE WHEN sysidx.filter_definition is not null THEN ' WHERE ' + sysidx.filter_definition + '' ELSE '' END + ' WITH (MAXDOP = 64, ONLINE = OFF, DROP_EXISTING = OFF); ' as [tsql_CREATE], 'IF EXISTS (SELECT TOP 1 NULL FROM sys.indexes (NOLOCK) WHERE object_name([object_id]) = ''' + object_name(sysidx.[object_id]) + ''' AND [name] = ''' + sysidx.[name] + ''') DROP INDEX [' + sysidx.[name] + '] ON [' + object_name(sysidx.[object_id]) + ']; ' as [tsql_DROP] FROM sys.indexes sysidx LEFT OUTER JOIN sys.dm_db_index_usage_stats idxusg ON sysidx."object_id" = idxusg."object_id" AND sysidx."index_id" = idxusg."index_id" JOIN ( SELECT Tab.[name] AS TableName, Ind.[name] AS IndexName, SUBSTRING (( SELECT ', [' + AC.name + ']' FROM sys.[tables] AS T INNER JOIN sys.[indexes] I ON T.[object_id] = I.[object_id] INNER JOIN sys.[index_columns] IC ON I.[object_id] = IC.[object_id] AND I.[index_id] = IC.[index_id] INNER JOIN sys.[all_columns] AC ON T.[object_id] = AC.[object_id] AND IC.[column_id] = AC.[column_id] WHERE Ind.[object_id] = I.[object_id] AND Ind.index_id = I.index_id AND IC.is_included_column = 0 ORDER BY IC.key_ordinal FOR XML PATH ('')) , 3, 8000) AS key_columns, SUBSTRING (( SELECT ', [' + AC.name + ']' FROM sys.[tables] AS T INNER JOIN sys.[indexes] I ON T.[object_id] = I.[object_id] INNER JOIN sys.[index_columns] IC ON I.[object_id] = IC.[object_id] AND I.[index_id] = IC.[index_id] INNER JOIN sys.[all_columns] AC ON T.[object_id] = AC.[object_id] AND IC.[column_id] = AC.[column_id] WHERE Ind.[object_id] = I.[object_id] AND Ind.index_id = I.index_id AND IC.is_included_column = 1 ORDER BY IC.key_ordinal FOR XML PATH ('')) , 3, 8000) AS included_columns FROM sys.[indexes] Ind INNER JOIN sys.[tables] AS Tab ON Tab.[object_id] = Ind.[object_id] INNER JOIN sys.[schemas] AS Sch ON Sch.[schema_id] = Tab.[schema_id] UNION SELECT Tab.[name] AS TableName, Ind.[name] AS IndexName, SUBSTRING (( SELECT ', [' + AC.name + ']' FROM sys.[views] AS T INNER JOIN sys.[indexes] I ON T.[object_id] = I.[object_id] INNER JOIN sys.[index_columns] IC ON I.[object_id] = IC.[object_id] AND I.[index_id] = IC.[index_id] INNER JOIN sys.[all_columns] AC ON T.[object_id] = AC.[object_id] AND IC.[column_id] = AC.[column_id] WHERE Ind.[object_id] = I.[object_id] AND Ind.index_id = I.index_id AND IC.is_included_column = 0 ORDER BY IC.key_ordinal FOR XML PATH ('')) , 3, 8000) AS key_columns, SUBSTRING (( SELECT ', [' + AC.name + ']' FROM sys.[views] AS T INNER JOIN sys.[indexes] I ON T.[object_id] = I.[object_id] INNER JOIN sys.[index_columns] IC ON I.[object_id] = IC.[object_id] AND I.[index_id] = IC.[index_id] INNER JOIN sys.[all_columns] AC ON T.[object_id] = AC.[object_id] AND IC.[column_id] = AC.[column_id] WHERE Ind.[object_id] = I.[object_id] AND Ind.index_id = I.index_id AND IC.is_included_column = 1 ORDER BY IC.key_ordinal FOR XML PATH ('')) , 3, 8000) AS included_columns FROM sys.[indexes] Ind INNER JOIN sys.[views] AS Tab ON Tab.[object_id] = Ind.[object_id] INNER JOIN sys.[schemas] AS Sch ON Sch.[schema_id] = Tab.[schema_id] ) idxcol ON object_name(sysidx.[object_id]) = idxcol.TableName AND sysidx.[name] = idxcol.IndexName WHERE object_name(sysidx.[object_id]) not like 'ssi%' AND sysidx.[name] like 'ssi%' or sysidx.[name] like 'missing_index_%' ORDER BY 1,3,4 Cumulative Update: Für den SQL Server stellt Microsoft regelmäßig Updates zur Verfügung. Diese werden nicht automatisch bei Windows Updates bereitgestellt. Meines Wissens werden lediglich Service Packs für den SQL Server in Windows Updates bereitgestellt. Zwischen dem letzten Service Pack und dem letzten Cumulative Update (CU) können in der Realität Jahre liegen. Es ist daher ratsam ab und an den SQL Server zu aktualisieren. Eine Übersicht der SQL Server Versionen, Service Packs & Cumulative Updates inkl. Downloadlinks findet ihr hier: http://sqlserverbuilds.blogspot.de/ Für die Installation eines Cumulative Update benötigt ihr das davor veröffentliche Service Pack. Bei der Installation wird der SQL Server gestoppt. Es wird also ein Wartungsfenster benötigt. In der Regel dauert die Installation nicht zu lange. Aufteilung TempDB: Bei der TempDB handelt es sich um eine Systemdatenbank des SQL Servers. Stehen dem SQL Server mehr als ein CPU Kern zur Verfügung, kann die TempDB aufgeteilt werden. Pro lizenzierten Kern sollte es dann eine Tempdb Datei geben. Mit dem folgenden Skript kann die Tempdb aufgeteilt werden: ALTER DATABASE tempdb ADD FILE (NAME = tempdev2, FILENAME = 'W:\tempdb2.mdf', SIZE = 1024, FILEGROWTH = 1024); ALTER DATABASE tempdb ADD FILE (NAME = tempdev3, FILENAME = 'X:\tempdb3.mdf', SIZE = 1024, FILEGROWTH = 1024); ALTER DATABASE tempdb ADD FILE (NAME = tempdev4, FILENAME = 'Y:\tempdb4.mdf', SIZE = 1024, FILEGROWTH = 1024); GO Dabei kann die Tempdb auch auf verschiedene Festplatten aufgeteilt werden (siehe oben). Ob das nötig ist, ist im Einzelfall zu betrachten. Die TempDB kann über das SQL Management Studio gefunden werden. <img loading="lazy" decoding="async" class="alignnone wp-image-543 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_ManagementStudio.jpg" alt="" width="402" height="186" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_ManagementStudio.jpg 402w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_ManagementStudio-300x139.jpg 300w" sizes="auto, (max-width: 402px) 100vw, 402px" /> Bei vier Kernen sieht die TempDB nach der Aufteilung so aus. <img loading="lazy" decoding="async" class="alignnone wp-image-544" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_TempDB.jpg" alt="" width="887" height="367" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_TempDB.jpg 887w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_TempDB-300x124.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_TempDB-768x318.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_TempDB-665x275.jpg 665w" sizes="auto, (max-width: 887px) 100vw, 887px" /> Alternative Quelle dazu: https://tristanmaritz.wordpress.com/2015/05/15/dynamics-nav-performance-tempdb/ Wartungsjobs: Die Indexierung der Datenbank sollte regelmäßig durchgeführt werden. Dafür ist ein Wartungsjob, der einmal pro Woche durchgeführt werden sollte, empfehlenswert. Dafür werden für SQL Server 2014 oder ältere SQL Server Versionen ein manuelles Skript empfohlen. Dies ist in drei T-SQL Skripten aufgeteilt. – T-SQL Skript 1: Umstellung auf Sicherheitsmodell „Simple“ USE [master] GO ALTER DATABASE [Databasename] SET RECOVERY SIMPLE WITH NO_WAIT GO ALTER DATABASE [Databasename] SET RECOVERY SIMPLE GO – T-SQL Skript 2: Neuindexierung (Rebuild oder Reorganize) der Datenbank USE [Databasename] GO SET NOCOUNT ON; DECLARE @objectid int; DECLARE @indexid int; DECLARE @partitioncount bigint; DECLARE @schemaname nvarchar(130); DECLARE @objectname nvarchar(130); DECLARE @indexname nvarchar(130); DECLARE @partitionnum bigint; DECLARE @partitions bigint; DECLARE @frag float; DECLARE @command nvarchar(4000); -- Conditionally select tables and indexes from the sys.dm_db_index_physical_stats function -- and convert object and index IDs to names. SELECT object_id AS objectid, index_id AS indexid, partition_number AS partitionnum, avg_fragmentation_in_percent AS frag INTO #work_to_do FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, 'LIMITED') WHERE avg_fragmentation_in_percent &gt; 10.0 AND index_id &gt; 0;-- Declare the cursor for the list of partitions to be processed. DECLARE partitions CURSOR FOR SELECT * FROM #work_to_do;-- Open the cursor. OPEN partitions;-- Loop through the partitions. WHILE (1=1) BEGIN; FETCH NEXT FROM partitions INTO @objectid, @indexid, @partitionnum, @frag; IF @@FETCH_STATUS &lt; 0 BREAK; SELECT @objectname = QUOTENAME(o.name), @schemaname = QUOTENAME(s.name) FROM sys.objects AS o JOIN sys.schemas as s ON s.schema_id = o.schema_id WHERE o.object_id = @objectid; SELECT @indexname = QUOTENAME(name) FROM sys.indexes WHERE object_id = @objectid AND index_id = @indexid; SELECT @partitioncount = count (*) FROM sys.partitions WHERE object_id = @objectid AND index_id = @indexid;-- 30 is an arbitrary decision point at which to switch between reorganizing and rebuilding. IF @frag &lt; 30.0 SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REORGANIZE'; IF @frag &gt;= 30.0 SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REBUILD'; IF @partitioncount &gt; 1 SET @command = @command + N' PARTITION=' + CAST(@partitionnum AS nvarchar(10)); EXEC (@command); PRINT N'Executed: ' + @command; END;-- Close and deallocate the cursor. CLOSE partitions; DEALLOCATE partitions;-- Drop the temporary table. DROP TABLE #work_to_do; GO – T-SQL Skript 3: Umstellung auf Recovery Mode Full -- Change security model back USE [master] GO ALTER DATABASE [Databasename] SET RECOVERY FULL WITH NO_WAIT GO ALTER DATABASE [Databasename] SET RECOVERY FULL GO Ab SQL Server 2016 ist kein spezielles Skript mehr notwendig. Die Wartungspläne „Index neu organisieren“ und „Index neu erstellen“ können mittlerweile konfiguriert werden. Dabei bleiben die Skripte zur Umstellung des Recovery Modes bestehen. Lediglich das zweite T-SQL Skript (siehe oben) wird durch die Standardwartungspläne ersetzt. <img loading="lazy" decoding="async" class="alignnone wp-image-547 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_SQLWartungsjob_IndexierungBoardMittel.jpg" alt="" width="870" height="481" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_SQLWartungsjob_IndexierungBoardMittel.jpg 870w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_SQLWartungsjob_IndexierungBoardMittel-300x166.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_SQLWartungsjob_IndexierungBoardMittel-768x425.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_SQLWartungsjob_IndexierungBoardMittel-665x368.jpg 665w" sizes="auto, (max-width: 870px) 100vw, 870px" /> <img loading="lazy" decoding="async" class="alignnone wp-image-548 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_SQLWartungsjob_IndexierungBoardMittel2.jpg" alt="" width="613" height="864" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_SQLWartungsjob_IndexierungBoardMittel2.jpg 613w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_SQLWartungsjob_IndexierungBoardMittel2-213x300.jpg 213w" sizes="auto, (max-width: 613px) 100vw, 613px" /> <img loading="lazy" decoding="async" class="alignnone wp-image-549 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_SQLWartungsjob_IndexierungBoardMittel3.jpg" alt="" width="611" height="532" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_SQLWartungsjob_IndexierungBoardMittel3.jpg 611w, https://robert-dynamicsnav.de/wp-content/uploads/2018/03/1803_SQLWartungsjob_IndexierungBoardMittel3-300x261.jpg 300w" sizes="auto, (max-width: 611px) 100vw, 611px" /> Weitere Tipps Antivirensoftware: Sollte eine Antivirensoftware auf der Maschine des SQL Servers oder der Dynamics NAV Service Tier installiert sein, dann sollte diese auch richtig konfiguriert werden.Auf dem SQL Server sollte keine Echtzeitüberprüfung auf Systemdatenbankdateien oder normale Datenbankdateien erfolgen. Dazu gibt es auch detaillierte Informationen von Microsoft: https://support.microsoft.com/de-lu/help/309422/how-to-choose-antivirus-software-to-run-on-computers-that-are-running Auf dem Dynamics NAV Ordner sollten die Programmverzeichnisse von Dynamics NAV ausgeschlossen werden. Bei Performanceproblemen lohnt es sich auch mal, den Vorgang in einer Umgebung ohne oder mit deaktivierten Antivirensoftware nochmal zu testen. Antivirensoftware kann in bestimmten Situationen die Performance massiv verschlechtern. Hardware: Bei der Hardware gibt es zwei Empfehlungen für Dynamics NAV und den SQL Server: – Die Hardware (CPU, RAM, Festplatten) sollten exklusiv zur Verfügung gestellt werden. – Verwendet falls möglich SSD Festplatten für die Datenbankdateien. Das wird die Performance erheblich steigern.Weitere Anforderungen an die Hardware hängen sicherlich von den spezifischen Anforderungen bzw. gleichzeitigen Nutzerzugriffen ab. Ich hoffe das diese Tipps euch weiterhelfen. Einige Tipps habe ich durch die Zusammenarbeit mit Jörg Stryk und meinen Kollegen in diversen Projekten gelernt. Schaut auf jeden Fall auch bei ihm vorbei: http://blog.stryk.info/. The post Dynamics NAV / SQL Server Performance Tipps & Tricks first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Hallo Leute, heute möchte ich über ein sehr spezielles Thema sprechen. Vor einigen Jahren habe ich das erste Mal davon gehört und als mir ein Kollege dieses spezielle Verhalten von Dynamics NAV erklärte, konnte ich es nicht glauben. Ich erstellte mir direkt eine Testdatenbank und wollte es ausprobieren. Erstaunlicherweise konnte ich das Verhalten sofort reproduzieren… Weiterlesen » The post Die dunkle Seite des Validate Triggers first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Hallo Leute, heute möchte ich über ein sehr spezielles Thema sprechen. Vor einigen Jahren habe ich das erste Mal davon gehört und als mir ein Kollege dieses spezielle Verhalten von Dynamics NAV erklärte, konnte ich es nicht glauben. Ich erstellte mir direkt eine Testdatenbank und wollte es ausprobieren. Erstaunlicherweise konnte ich das Verhalten sofort reproduzieren und das in verschiedenen Dynamics NAV Versionen. An diesem Punkt realisierte ich, dass dieses Verhalten einen Grund haben muss. Es handelt sich bei dem Problem um das Rollback Verhalten bei Programmierungen im Validate Trigger eines Tabellenfeldes. Wer das Thema kennt, braucht vermutlich nicht weiterlesen, aber wer jetzt glaubt, das dort gar kein Problem existiert, darf gerne folgendes Experiment mit mir versuchen. Dafür nutze ich eine Dynamics NAV 2017 CU 9 Cronus Demo Datenbank. Das ist zum jetzigen Zeitpunkt das aktuellste Build für Dynamics NAV 2017. Stellen wir uns folgendes Szenario vor: Beim Ändern des Feldes „Beschreibung“ in der Verkaufszeile soll ein Eintrag in einer neuen Tabelle geschrieben werden. Dieser beinhaltet den Primärschlüssel der Verkaufszeile und eine laufende Nummer, sowie die Beschreibung. Jedes Mal, wenn die Beschreibung geändert wird, soll ein Eintrag geschrieben werden. Mir ist dabei bewusst, dass es auch die Änderungsprotokollierung in Dynamics NAV gibt, aber die Funktion wollen wir in unseren Beispiel nicht verwenden. Wir öffnen also die Entwicklungsumgebung unserer Dynamics NAV 2017 Demo Datenbank und legen zuerst eine Tabelle an: Object Designer öffnen und neue Tabelle erstellen <img loading="lazy" decoding="async" class="alignnone wp-image-478 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_1_NeueTabelle-1.jpg" alt="" width="642" height="352" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_1_NeueTabelle-1.jpg 642w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_1_NeueTabelle-1-300x164.jpg 300w" sizes="auto, (max-width: 642px) 100vw, 642px" /> Wir legen diese Felder an: Primärschlüsselfelder der Verkaufszeile (Belegart, Belegnr., Zeilennr.), eine Lfd. Nr. als fortlaufende Nummer und das Feld Beschreibung: <img loading="lazy" decoding="async" class="alignnone wp-image-479 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_2_Felder-1.jpg" alt="" width="809" height="283" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_2_Felder-1.jpg 809w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_2_Felder-1-300x105.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_2_Felder-1-768x269.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_2_Felder-1-665x233.jpg 665w" sizes="auto, (max-width: 809px) 100vw, 809px" /> Die Tabelle weise ich der Nummer 50000 zu und vergebe den Namen „Description Log“ <img loading="lazy" decoding="async" class="alignnone wp-image-480 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_3_Tabelleneigenschaften-1.jpg" alt="" width="525" height="341" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_3_Tabelleneigenschaften-1.jpg 525w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_3_Tabelleneigenschaften-1-300x195.jpg 300w" sizes="auto, (max-width: 525px) 100vw, 525px" /> Als Primärschlüssel verwenden wir folgende Felder: „Belegart“, „Belegnr.“, „Zeilennr.“, „Lfd. Nr.“ <img loading="lazy" decoding="async" class="alignnone wp-image-481 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_4_Schlüssel-1.jpg" alt="" width="464" height="291" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_4_Schlüssel-1.jpg 464w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_4_Schlüssel-1-300x188.jpg 300w" sizes="auto, (max-width: 464px) 100vw, 464px" /> Mit der Tabelle haben wir die Grundlage zum Speichern von Daten. Zusätzlich erstellen wir noch eine Page zur Anzeige der Daten. Dafür führe ich folgende Schritte durch: Erstelle eine neue Page 50000 „Description Log List“ Füge die Felder „Lfd. Nr.“ und Beschreibung hinzu. Setze die Page auf nicht editierbar. <img loading="lazy" decoding="async" class="alignnone wp-image-482 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_5_PageBeschreibungsProtokoll.jpg" alt="" width="791" height="292" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_5_PageBeschreibungsProtokoll.jpg 791w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_5_PageBeschreibungsProtokoll-300x111.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_5_PageBeschreibungsProtokoll-768x284.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_5_PageBeschreibungsProtokoll-665x245.jpg 665w" sizes="auto, (max-width: 791px) 100vw, 791px" /> Nun füge ich die Page in die Actions der Verkaufsauftragssubpage hinzu: Page 46 „Sales Order Subform“ im Designer öffnen Aktionen öffnen Eine neue Aktion am Ende der Gruppe „Zeile“ – „Verknüpfte Information“ hinzufügen Die neue Action mit der Page 50000 „Description Log List“ verknüpfen <img loading="lazy" decoding="async" class="alignnone wp-image-483 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_6_AnpassungVerkaufsauftragl.jpg" alt="" width="1424" height="633" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_6_AnpassungVerkaufsauftragl.jpg 1424w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_6_AnpassungVerkaufsauftragl-300x133.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_6_AnpassungVerkaufsauftragl-768x341.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_6_AnpassungVerkaufsauftragl-1024x455.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_6_AnpassungVerkaufsauftragl-665x296.jpg 665w" sizes="auto, (max-width: 1424px) 100vw, 1424px" /> Im Verkaufsauftrag haben wir nun die Action zum Anzeigen des Beschreibungsprotokoll: <img loading="lazy" decoding="async" class="alignnone wp-image-484 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_7_AufrufBeschreibungsprotokolll.jpg" alt="" width="1004" height="684" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_7_AufrufBeschreibungsprotokolll.jpg 1004w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_7_AufrufBeschreibungsprotokolll-300x204.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_7_AufrufBeschreibungsprotokolll-768x523.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_7_AufrufBeschreibungsprotokolll-60x42.jpg 60w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_7_AufrufBeschreibungsprotokolll-665x453.jpg 665w" sizes="auto, (max-width: 1004px) 100vw, 1004px" /> Als letztes bauen wir noch eine Anpassung in die Tabelle 37 im Feld „Beschreibung“ ein um die Änderungen zu protokollieren. <img loading="lazy" decoding="async" class="alignnone wp-image-487 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_8_DescriptionValidate2.jpg" alt="" width="1196" height="648" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_8_DescriptionValidate2.jpg 1196w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_8_DescriptionValidate2-300x163.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_8_DescriptionValidate2-768x416.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_8_DescriptionValidate2-1024x555.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_8_DescriptionValidate2-665x360.jpg 665w" sizes="auto, (max-width: 1196px) 100vw, 1196px" /> Diese Anpassung dient nur der Demonstration und ist keine Empfehlung zur Umsetzung. Daran können wir aber feststellen, was das eigentlich Problem ist. Ich ändere nun die Beschreibung von: „TOKYO Gästestuhl, blau“ auf „TOKYO Gästestuhl, blau2„ „TOKYO Gästestuhl, blau2“ auf „TOKYO Gästestuhl, blau1„ „TOKYO Gästestuhl, blau1“ auf „TOKYO Gästestuhl, blau3„ <img loading="lazy" decoding="async" class="alignnone wp-image-488 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_9_Protokolleinträge.jpg" alt="" width="976" height="587" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_9_Protokolleinträge.jpg 976w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_9_Protokolleinträge-300x180.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_9_Protokolleinträge-768x462.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_9_Protokolleinträge-665x400.jpg 665w" sizes="auto, (max-width: 976px) 100vw, 976px" /> Es werden drei Einträge in unserem Beschreibungsprotokoll angezeigt und das ist auch mein gewünschtes Ergebnis. Anscheinend funktioniert alles prima! Nun programmiere ich einen Error in den Modify Trigger der Tabelle 37. Sowas kann man sehr gut vergleichen mit einer Prüfung, ob der Beleg überhaupt „Offen“ ist (Beispiel „TestStatusOpen“ Funktion). Solche Prüfungen sind in Tabellentriggern nicht unüblich. Zu Demonstrationszwecken nehmen wir hier einen harten Error ohne Bedingung. <img loading="lazy" decoding="async" class="alignnone wp-image-489 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_10_ErrorModify.jpg" alt="" width="1076" height="687" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_10_ErrorModify.jpg 1076w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_10_ErrorModify-300x192.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_10_ErrorModify-768x490.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_10_ErrorModify-1024x654.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_10_ErrorModify-665x425.jpg 665w" sizes="auto, (max-width: 1076px) 100vw, 1076px" /> Was passiert nun, wenn wir die Beschreibung ein weiteres Mal ändern: Ich trage TOKYO Gästestuhl, blau4 in das Feld Beschreibung ein und drücke Enter. Ich stehe nun im Feld Menge. <img loading="lazy" decoding="async" class="alignnone wp-image-490 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_11_ValidateTest.jpg" alt="" width="633" height="194" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_11_ValidateTest.jpg 633w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_11_ValidateTest-300x92.jpg 300w" sizes="auto, (max-width: 633px) 100vw, 633px" /> Anschließend verlasse ich die Zeile, indem ich die Pfeiltaste nach unten drücke: <img loading="lazy" decoding="async" class="alignnone wp-image-491 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_12_Zeileverlassen.jpg" alt="" width="713" height="446" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_12_Zeileverlassen.jpg 713w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_12_Zeileverlassen-300x188.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_12_Zeileverlassen-665x416.jpg 665w" sizes="auto, (max-width: 713px) 100vw, 713px" /> An dieser Stelle bekomme ich nun den Fehler „Stop“, da nun mit dem Verlassen der Zeile der OnModify Trigger der Tabelle aufgerufen wurde. Ich erwarte nun einen kompletten Rollback: Setze die Verkaufszeile auf „TOKYO Gästestuhl, blau3“ zurück Schreibe keinen Eintrag in der Beschreibungsprotokoll Tabelle Ich drücke nun F5 und löse den Fehler auf, indem ich meine Änderung verwerfe. Anschließend erhalte ich folgendes Ergebnis: <img loading="lazy" decoding="async" class="alignnone wp-image-492 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_13_Ergebnis.jpg" alt="" width="955" height="521" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_13_Ergebnis.jpg 955w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_13_Ergebnis-300x164.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_13_Ergebnis-768x419.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2017/09/DunkleSeiteValidate_13_Ergebnis-665x363.jpg 665w" sizes="auto, (max-width: 955px) 100vw, 955px" /> Wir können klar erkennen, dass der aktuelle Datensatz zurückgesetzt wurde und die Tabelle „Beschreibung Protokollliste“ nicht zurückgesetzt wurde. Was lernen wir daraus? Der Rollback auf der Zeile klappt wunderbar. Der Eintrag in meiner Protokolltabelle ist aber trotzdem vorhanden. Hier fand kein Rollback statt. Warum ist das so? Beim Validieren eines Feldes in einer Page wird der Validate Trigger der Tabelle durchlaufen. Solange der Cursor aber noch in der aktuellen Zeile stehen bleibt, wurde der OnModify Trigger noch nicht durchlaufen. Dynamics NAV speichert aber dennoch alle Änderungen an Fremdtabellen (in unserem Beispiel die Tabelle 50000 „Description Log“) bereits in der Datenbank. Verlasse ich nun die Zeile, wird nur der Rollback auf den aktuellen Record durchgeführt. Alle anderen Transaktionen auf andere Tabellen sind davon nicht betroffen, da diese bereits comitted sind. Ich vermute, dass dies gewollt ist, damit die Transaktion nicht solange gesperrt wird, wie der Cursor auf dem Datensatz steht. Da zwischen einen Validate in einer Page und dem tatsächlichen Modify auf der Tabelle mehrere Minuten liegen könnten, ist das wohl der Kompromiss. Deswegen spreche ich von der dunklen Seite des Validate Triggers. Als Faustregel kann folgendes abgeleitet werden: Erstelle, ändere, lösche oder benenne keine Datensätze von anderen Recordvariablen in einem Validate Trigger einer Tabelle. Füge den Code stattdessen in den OnInsert, OnModify, OnRename oder OnDelete ein. Hier funktioniert auch der Rollback auf anderen Record Variablen. Ich hoffe das dieser Beitrag einigen Leuten hilft und sensibilisiert. The post Die dunkle Seite des Validate Triggers first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Dynamics NAV – Verwendung von Queries #2 – Generische Diagramme
Hallo Leute, im Beitrag Dynamics NAV – Verwendung von Queries habe ich über einen nützlichen Anwendungsfall von Queries (Abfragen) gesprochen. In diesem Beitrag möchte ich über eine weitere Einsatzmöglichkeit von Queries, den generischen Diagrammen, berichten. Wer sich zuerst einlesen möchte, der kann sich den Beitrag im MSDN ansehen (How to: Create Generic Charts). Des Weiteren gib es hier… Weiterlesen » The post Dynamics NAV – Verwendung von Queries #2 – Generische Diagramme first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Hallo Leute, im Beitrag Dynamics NAV – Verwendung von Queries habe ich über einen nützlichen Anwendungsfall von Queries (Abfragen) gesprochen. In diesem Beitrag möchte ich über eine weitere Einsatzmöglichkeit von Queries, den generischen Diagrammen, berichten. Wer sich zuerst einlesen möchte, der kann sich den Beitrag im MSDN ansehen (How to: Create Generic Charts). Des Weiteren gib es hier auch eine Einleitung auf deutsch, wie generische Diagramme eingerichtet werden können (Microsoft Dynamics NAV 2013 – neue Auswertungsmöglichkeiten). In den generischen Diagrammen kann ich grundsätzlich zwischen zwei Datenquellen wählen: Tabellen und deren Felder Abfragen (Queries) und deren Spalten & Filter <img loading="lazy" decoding="async" class="alignnone wp-image-427" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_1_GenerischeDiagramme.jpg" alt="queries2_1_generischediagramme" width="954" height="588" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_1_GenerischeDiagramme.jpg 1183w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_1_GenerischeDiagramme-300x185.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_1_GenerischeDiagramme-768x473.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_1_GenerischeDiagramme-1024x631.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_1_GenerischeDiagramme-665x410.jpg 665w" sizes="auto, (max-width: 954px) 100vw, 954px" /> Generische Diagramme bieten sich für eine schnelle Auswertung bestimmter Daten an. In meinem Beispiel befassen wir uns daher mit Kunden- und Lieferanten-Stammdaten. Wir wollen beispielsweise wissen, welche Kunden oder Lieferanten ein Saldo von höher als 1.000 bzw. 10.000 € aufweisen. Wir schauen uns daher die Debitoren mit einem Saldo von mehr als 10.000 € an. Diese Information steht uns im Microsoft Standard über das Feld Saldo in der Kundentabelle (Tabelle 18 Customer) und in der Lieferantentabelle (Tabelle 23 Vendor) bereits mit dem Flowfield „Balance“ (Saldo) zur Verfügung. <img loading="lazy" decoding="async" class="alignnone wp-image-428" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_2_Flowfield_Balance.jpg" alt="queries2_2_flowfield_balance" width="878" height="377" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_2_Flowfield_Balance.jpg 1146w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_2_Flowfield_Balance-300x129.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_2_Flowfield_Balance-768x330.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_2_Flowfield_Balance-1024x440.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_2_Flowfield_Balance-665x285.jpg 665w" sizes="auto, (max-width: 878px) 100vw, 878px" /> Wenn wir nun versuchen unsere Anforderung mit einem generischen Diagramm umzusetzen, dann könnte das so aussehen: ID = T18_50000 (Tabelle 18 / 50000 erstes individuelles generisches Diagramm) Name = Debitor (Saldo MW > 10000) Herkunftsart = Tabelle Herkunfts-ID = 18 Erforderliche Kennzahl (Balance LCY) -> Saldo (MW) y-Achse – Titel = Saldo (MW) x-Achse – Feld = Name x-Achse – Titel = Name Beschreibung = Zeigt alle Debitoren mit einem Saldo (MW) > 10.000 € Filter auf das Feld Balance (LCY) = „>10000“ <img loading="lazy" decoding="async" class="alignnone wp-image-429 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_3_GenerischeDiagramm_FlowfieldBalance.jpg" alt="queries2_3_generischediagramm_flowfieldbalance" width="1685" height="987" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_3_GenerischeDiagramm_FlowfieldBalance.jpg 1685w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_3_GenerischeDiagramm_FlowfieldBalance-300x176.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_3_GenerischeDiagramm_FlowfieldBalance-768x450.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_3_GenerischeDiagramm_FlowfieldBalance-1024x600.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_3_GenerischeDiagramm_FlowfieldBalance-665x390.jpg 665w" sizes="auto, (max-width: 1685px) 100vw, 1685px" /> Nun integrieren wir das Diagramm in unserer Rollencenter. Dafür führe ich folgende Schritte durch: Öffnen des Rollencenters (Ich nutze für mein Beispiel das Rollencenter 9007 -> Profil Einkäufer) Anpassen der Rollencenterseite <img loading="lazy" decoding="async" class="alignnone wp-image-430" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_4_GenerischeDiagramm_Rollencenter1.jpg" alt="queries2_4_generischediagramm_rollencenter1" width="523" height="304" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_4_GenerischeDiagramm_Rollencenter1.jpg 668w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_4_GenerischeDiagramm_Rollencenter1-300x174.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_4_GenerischeDiagramm_Rollencenter1-665x386.jpg 665w" sizes="auto, (max-width: 523px) 100vw, 523px" /> Diagrammabschnitt hinzufügen und somit ein „Leeres Diagramm“ im Layout des Rollencenters erzeugen. <img loading="lazy" decoding="async" class="alignnone wp-image-431" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_5_GenerischeDiagramm_Rollencenter2.jpg" alt="queries2_5_generischediagramm_rollencenter2" width="699" height="450" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_5_GenerischeDiagramm_Rollencenter2.jpg 832w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_5_GenerischeDiagramm_Rollencenter2-300x193.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_5_GenerischeDiagramm_Rollencenter2-768x495.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_5_GenerischeDiagramm_Rollencenter2-665x428.jpg 665w" sizes="auto, (max-width: 699px) 100vw, 699px" /> Im Rollencenter das „Leere Diagramm“ auswählen und dort auf Anpassen klicken: <img loading="lazy" decoding="async" class="alignnone wp-image-432" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_6_GenerischeDiagramm_Rollencenter3.jpg" alt="queries2_6_generischediagramm_rollencenter3" width="1220" height="240" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_6_GenerischeDiagramm_Rollencenter3.jpg 1322w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_6_GenerischeDiagramm_Rollencenter3-300x59.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_6_GenerischeDiagramm_Rollencenter3-768x151.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_6_GenerischeDiagramm_Rollencenter3-1024x201.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_6_GenerischeDiagramm_Rollencenter3-665x131.jpg 665w" sizes="auto, (max-width: 1220px) 100vw, 1220px" /> Das individuelle Diagramm auswählen „T18_50000“ und mit „OK“ bestätigen. <img loading="lazy" decoding="async" class="alignnone wp-image-434" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_7_GenerischeDiagramm_Rollencenter4.jpg" alt="queries2_7_generischediagramm_rollencenter4" width="456" height="381" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_7_GenerischeDiagramm_Rollencenter4.jpg 507w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_7_GenerischeDiagramm_Rollencenter4-300x251.jpg 300w" sizes="auto, (max-width: 456px) 100vw, 456px" /> Nun können wir uns das Ergebnis ansehen: <img loading="lazy" decoding="async" class="alignnone wp-image-435 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_8_GenerischeDiagramm_Rollencenter5.jpg" alt="queries2_8_generischediagramm_rollencenter5" width="567" height="562" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_8_GenerischeDiagramm_Rollencenter5.jpg 642w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_8_GenerischeDiagramm_Rollencenter5-150x150.jpg 150w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_8_GenerischeDiagramm_Rollencenter5-300x297.jpg 300w" sizes="auto, (max-width: 567px) 100vw, 567px" /> Je nach Anzahl der detaillierten Debitorenposten kann die Performance hier stark schwanken. Ich habe per Stapelverarbeitung 500.000 detaillierte Debitorenposten in einem Cronus Mandanten erzeugt. Trotz meiner sehr leistungsstarken Testumgebung benötigt das generische Diagramm nun ca. 30 Sekunden zum Anzeigen der Daten. Es kann also festhalten werden: Umso mehr detaillierte Debitorenposten vorhanden sind umso länger braucht das Diagramm. Das liegt einfach daran, dass die folgenden Kriterien ungünstig sind: Berechnung eines Flowfields pro Debitor Filterung auf ein FlowField So sieht das dann für den Anwender aus und das jedes Mal, wenn die Rollencenterseite geöffnet wird. Das ist dann nicht mehr so schön. <img loading="lazy" decoding="async" class="alignnone wp-image-436" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_9_GenerischeDiagramm_Rollencenter6.jpg" alt="queries2_9_generischediagramm_rollencenter6" width="567" height="419" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_9_GenerischeDiagramm_Rollencenter6.jpg 663w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_9_GenerischeDiagramm_Rollencenter6-300x222.jpg 300w" sizes="auto, (max-width: 567px) 100vw, 567px" /> Die Alternative dazu stellt eine Query da, die wesentlich schneller ist. Ich orientiere mich am Flowfield, da ich das exakt gleiche Ergebnis haben möchte. So sieht dann meine Query aus: No. – aus der Debitorentabelle Name – aus der Debitorentabelle Amount / Amount (LCY) aus der Detaillierten Debitorenpostentabelle und die Verknüpfung über das Feld Debitorennr. <img loading="lazy" decoding="async" class="alignnone wp-image-437" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_10_QueryDebitorenSalden.jpg" alt="queries2_10_querydebitorensalden" width="1028" height="242" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_10_QueryDebitorenSalden.jpg 1257w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_10_QueryDebitorenSalden-300x71.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_10_QueryDebitorenSalden-768x181.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_10_QueryDebitorenSalden-1024x241.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_10_QueryDebitorenSalden-665x157.jpg 665w" sizes="auto, (max-width: 1028px) 100vw, 1028px" /> Die Einrichtung des generischen Diagramms ist fast identisch mit der Einrichtung der Debitorentabelle (siehe oben). Folgende Änderungen sind vorhanden: Herkunftart = Abfrage Herkunfts-ID: 50001 Erforderliche Kennzahl -> Aggragation „Summe“ Ansonsten sind nur die Feldnamen etwas anders. <img loading="lazy" decoding="async" class="alignnone wp-image-438" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_11_QueryEinrichtungGenerrischesDiagramm.jpg" alt="queries2_11_queryeinrichtunggenerrischesdiagramm" width="1224" height="707" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_11_QueryEinrichtungGenerrischesDiagramm.jpg 1698w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_11_QueryEinrichtungGenerrischesDiagramm-300x173.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_11_QueryEinrichtungGenerrischesDiagramm-768x443.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_11_QueryEinrichtungGenerrischesDiagramm-1024x591.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_11_QueryEinrichtungGenerrischesDiagramm-665x384.jpg 665w" sizes="auto, (max-width: 1224px) 100vw, 1224px" /> Nun können wir das Diagramm im Rollencenter austauschen und müssen dann den Client einmal neustarten: <img loading="lazy" decoding="async" class="alignnone wp-image-439" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_12_EinbindungRollencenter.jpg" alt="queries2_12_einbindungrollencenter" width="433" height="363" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_12_EinbindungRollencenter.jpg 508w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Queries2_12_EinbindungRollencenter-300x251.jpg 300w" sizes="auto, (max-width: 433px) 100vw, 433px" /> Nach dem Neustart ist das generische Diagramm sofort geladen. Keine Wartezeit! Hier ist die Query wesentlich schneller als die Flowfield Variante. Auch wenn ich viel Kritik über Query gelesen habe und es auch berechtigte Kritik gibt, weil es beispielsweise keine Standardintegration von Queries in Seiten oder Berichten als SourceTable gibt, so darf man nicht vergessen, dass Queries in manchen Bereichen sehr große Vorteile aufweisen können. Das Query Objekt (Debitorensalden) könnt ihr hier herunterladen: 161030_CustomerBalanceQuery.zip The post Dynamics NAV – Verwendung von Queries #2 – Generische Diagramme first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Hallo liebe Leser, mit Dynamics NAV 2013 wurde uns die Objektart Query (MSDN – Queries / MSDN – Working with Queries) vorgestellt und von Microsoft zur Verfügung gestellt. In der letzten Zeit sah ich mehrere alte Umsetzungen oder auch neue Anfragen zu Programmierungen, wo es sich förmlich anbot Queries als Objektart zu verwenden. Daher möchte ich heute kurz darauf… Weiterlesen » The post Dynamics NAV – Verwendung von Queries first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Hallo liebe Leser, mit Dynamics NAV 2013 wurde uns die Objektart Query (MSDN – Queries / MSDN – Working with Queries) vorgestellt und von Microsoft zur Verfügung gestellt. In der letzten Zeit sah ich mehrere alte Umsetzungen oder auch neue Anfragen zu Programmierungen, wo es sich förmlich anbot Queries als Objektart zu verwenden. Daher möchte ich heute kurz darauf eingehen, wo und wann sich die Verwendung von Queries lohnen kann und habe dafür auch ein Beispiel vorbereitet. Meiner Meinung nach gibt es zwei signifikante Unterschiede zwischen RETEAP UNTIL NEXT Schleifen und Queries: Mit einem FINDSET oder FIND(‚-‚) werden immer alle Felder aus der entsprechenden Tabelle geholt. Bei der Query ruft man nur die benötigten Felder ab. Bei verschachtelten Schleifen (Beispiel Debitor -> Debitorenposten) wird zu jedem Debitor einzeln alle gefilterten Debitorenposten geholt. Eine Query holt diese Daten kombiniert, da das SQL Skript anders aufgebaut ist. Wie groß der Unterschied zwischen einer Query und verschachtelten Schleifen oder auch Datasets sein kann, werde ich an folgender Anforderung zeigen: „Erstelle einen Monatsbericht, der pro Monat und pro Mitarbeiter anzeigt, ob dieser mehr als 8 Stunden gearbeitet hat.“ Das Beispiel ist stark vereinfacht und bezieht sich jetzt auf folgende Tabellen: Ressource, Projektposten, (optional Projektbuchblattzeile). Wir befassen uns nur mit dem Ermitteln der erforderlichen Daten. Die Ausgabe und die Filterung lasse ich komplett außen vor. Das Dataset könnte beispielsweise so aussehen: Ressource –>Projektposten: Hierbei würden alle Projektposten einfach im Dataset übergeben und im RDL summiert. Alternativ dazu könnten wir die Daten auch im C/AL schon gruppieren (Buffertabelle) Die Laufzeit bei ca. 1 Millionen Projektposten beträgt bei mir ca. 42 Sekunden (nur die Verarbeitung im C/AL ohne Datasetübergabe oder Layout. <img loading="lazy" decoding="async" class="alignnone wp-image-408 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_1_Bericht1.jpg" alt="query_1_bericht1" width="877" height="379" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_1_Bericht1.jpg 1143w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_1_Bericht1-300x130.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_1_Bericht1-768x332.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_1_Bericht1-1024x443.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_1_Bericht1-665x287.jpg 665w" sizes="auto, (max-width: 877px) 100vw, 877px" /> Ressource –> Datum –> Projektposten: Pro Ressource bauen wir per Dataset eine Schleife über jeden Tag im Filter und laufen dann pro Tag durch die Projektposten der Ressource Die Laufzeit bei ca. 1 Millionen Projektposten beträgt bei mir auch hier ca. 42 Sekunden (nur die Verarbeitung im C/AL ohne Datasetübergabe oder Layout. <img loading="lazy" decoding="async" class="alignnone wp-image-409 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_2_Bericht2.jpg" alt="query_2_bericht2" width="905" height="328" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_2_Bericht2.jpg 1357w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_2_Bericht2-300x109.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_2_Bericht2-768x278.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_2_Bericht2-1024x371.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_2_Bericht2-665x241.jpg 665w" sizes="auto, (max-width: 905px) 100vw, 905px" /> <img loading="lazy" decoding="async" class="alignnone wp-image-410" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_3_Bericht2_2.jpg" alt="query_3_bericht2_2" width="915" height="386" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_3_Bericht2_2.jpg 1157w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_3_Bericht2_2-300x127.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_3_Bericht2_2-768x324.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_3_Bericht2_2-1024x432.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_3_Bericht2_2-665x280.jpg 665w" sizes="auto, (max-width: 915px) 100vw, 915px" /> <img loading="lazy" decoding="async" class="alignnone wp-image-411" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_4_Bericht2_3.jpg" alt="query_4_bericht2_3" width="636" height="263" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_4_Bericht2_3.jpg 928w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_4_Bericht2_3-300x124.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_4_Bericht2_3-768x318.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_4_Bericht2_3-665x275.jpg 665w" sizes="auto, (max-width: 636px) 100vw, 636px" /> Warum in diesem Fall nicht eine Query nutzen, die mir schon pro Ressource und pro Tag die summierte Menge ausgibt? Die Query muss dann so aussehen: <img loading="lazy" decoding="async" class="alignnone wp-image-412 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_5_QueryAlsErsatz.jpg" alt="query_5_queryalsersatz" width="1196" height="294" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_5_QueryAlsErsatz.jpg 1196w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_5_QueryAlsErsatz-300x74.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_5_QueryAlsErsatz-768x189.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_5_QueryAlsErsatz-1024x252.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_5_QueryAlsErsatz-665x163.jpg 665w" sizes="auto, (max-width: 1196px) 100vw, 1196px" /> Wir benötigen die Ressourcennummer, das Buchungsdatum und das summierte Feld Menge. Sobald wir „Method Type“ = Totals auf dem Feld Menge einstellen, bekommen alle anderen Felder den Haken „Group by“. Die Ressourcen-Tabelle wird über die Nummer mit der Projektpostentabelle über den DataItemLink verknüpft. Ein Hinweis an dieser Stelle. Wer meint, dass die Ressourcentabelle als DataItem unnötig ist, der hat in diesem Fall Recht. Sobald ich aber beispielsweise den Namen aus der Tabelle nutzen möchte, macht der Aufbau so mehr Sinn und ist daher meiner Meinung nach zielführender. Das war’s, mehr muss man nicht machen. Führen wir die Query einfach mal aus: <img loading="lazy" decoding="async" class="alignnone wp-image-413 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_6_QueryAlsErsatz_2.jpg" alt="query_6_queryalsersatz_2" width="358" height="559" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_6_QueryAlsErsatz_2.jpg 358w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_6_QueryAlsErsatz_2-192x300.jpg 192w" sizes="auto, (max-width: 358px) 100vw, 358px" /> Die Abfrage dauert keine 2 Sekunden, obwohl ich am 02.01.2016 1 Millionen Projektposten erstellt habe. Diese Query integriere ich nun in einen Bericht. Leider weiß ich nicht wie viele Einträge die Query hat, daher habe ich mich entschieden, die Query in eine temporäre Buffer Tabelle zu schreiben und die Buffertabelle dann noch komplett zu durchlaufen (Gibt dazu auch ein HowDoI Video für eine Debitoren TOP 10 Liste: How Do I: Create a Report Using a Query in Microsoft Dynamics NAV 2013 R2) <img loading="lazy" decoding="async" class="alignnone wp-image-414" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_7_QueryImReport_1.jpg" alt="query_7_queryimreport_1" width="977" height="259" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_7_QueryImReport_1.jpg 1139w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_7_QueryImReport_1-300x80.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_7_QueryImReport_1-768x204.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_7_QueryImReport_1-1024x272.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_7_QueryImReport_1-665x176.jpg 665w" sizes="auto, (max-width: 977px) 100vw, 977px" /> <img loading="lazy" decoding="async" class="alignnone wp-image-415 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_8_QueryImReport_2.jpg" alt="query_8_queryimreport_2" width="977" height="258" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_8_QueryImReport_2.jpg 1140w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_8_QueryImReport_2-300x79.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_8_QueryImReport_2-768x203.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_8_QueryImReport_2-1024x270.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_8_QueryImReport_2-665x176.jpg 665w" sizes="auto, (max-width: 977px) 100vw, 977px" /> <img loading="lazy" decoding="async" class="alignnone wp-image-416 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_9_QueryImReport_3.jpg" alt="query_9_queryimreport_3" width="797" height="594" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_9_QueryImReport_3.jpg 930w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_9_QueryImReport_3-300x224.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_9_QueryImReport_3-768x572.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/10/Query_9_QueryImReport_3-665x496.jpg 665w" sizes="auto, (max-width: 797px) 100vw, 797px" /> Die Laufzeit beträgt dann sage und schreibe 2 Sekunden. Für mich ist das ein Unterschied wie Tag und Nacht. Ok, ich habe nun keine Möglichkeit alle Felder der Tabelle für die Filterung des Anwenders zu nutzen, aber das ist meistens auch nicht nötig. Die benötigten Felder kann man entsprechend als Filter in der Query und als Filter in der Requestpage (ausprogrammiert) hinterlegen und das sorgt für einen erheblichen Performanceboost. Wer es selber ausprobieren möchte, kann die Objekte in einer Cronus DB ausführen. Ihr müsst Euch lediglich vorher genug Projektposten erstellen. FOB und TXT könnt ihr hier herunterladen: 161029_queryimreport.zip Wer sich damit noch nicht befasst hat, sollte mal einen Blick darauf werfen. The post Dynamics NAV – Verwendung von Queries first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Dynamics NAV 2016 – CU9 – Server Konfiguration RDLC Bericht – Word / Excel Export
Hi Leute, kurzes Update zu dem „cumulative Update 9 (CU9)“ von Dynamics NAV 2016. Ich hatte gedacht, dass dieses Feature endlich das Problem löst, dass man Rechnungen beispielsweise nicht mehr nach Excel exportieren kann, aber leider bietet das neue Feature nur einen geringen Mehrwert. Warum ich das so sehe, werde ich nun näher erläutern. Im CU9 wurde ein… Weiterlesen » The post Dynamics NAV 2016 – CU9 – Server Konfiguration RDLC Bericht – Word / Excel Export first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Hi Leute, kurzes Update zu dem „cumulative Update 9 (CU9)“ von Dynamics NAV 2016. Ich hatte gedacht, dass dieses Feature endlich das Problem löst, dass man Rechnungen beispielsweise nicht mehr nach Excel exportieren kann, aber leider bietet das neue Feature nur einen geringen Mehrwert. Warum ich das so sehe, werde ich nun näher erläutern. Im CU9 wurde ein neues Feature in der Server Konfiguration hinzugefügt: „Add configuration setting for disabling saving reports with an RDLC layout as Microsoft Word or Microsoft Excel documents“ <img loading="lazy" decoding="async" class="alignnone wp-image-376 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/07/Report6_1_NewOptions.jpg" alt="Report6_1_NewOptions" width="1125" height="588" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/07/Report6_1_NewOptions.jpg 1125w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/Report6_1_NewOptions-300x157.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/Report6_1_NewOptions-768x401.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/Report6_1_NewOptions-1024x535.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/Report6_1_NewOptions-665x348.jpg 665w" sizes="auto, (max-width: 1125px) 100vw, 1125px" /> Damit gibt es drei neue Optionen im Register „Reports“: Enable Save as Excel on Request Pages of RDLC-layout Reports Enable Save as Word on Request Pages of RDLC-layout Reports Enable Save from Report PreView Die Option „Report PDF Font Embedding“ gab es schon früher und ist damit nichts Neues. Hier kann ich einstellen, ob die Schriftart in der PDF gespeichert werden soll oder ob nur ein Verweis erstellt werden soll. Der Vorteil liegt hier ganz klar in der Größe der PDF. Ich kann die PDF damit etwas verkleinern. Der Nachteil liegt auf der anderen Seite darin, dass bei Barcodes (Lösung per Schriftart) oder individuellen Schriftarten das PDF auf anderen PCs nicht so aussieht, wie es möglicherweise beim Ersteller dargestellt wird, der diese Schriftarten installiert hat. Die gleiche Option gibt es übrigens auch in den Berichtseigenschaften. Als Alternativlösung habe ich bereits über PDF Komprimierung mit Ghostskript berichtet. <img loading="lazy" decoding="async" class="alignnone wp-image-377 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/07/Report6_2_PDFFontEmbedding_Bericht.jpg" alt="Report6_2_PDFFontEmbedding_Bericht" width="455" height="496" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/07/Report6_2_PDFFontEmbedding_Bericht.jpg 455w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/Report6_2_PDFFontEmbedding_Bericht-275x300.jpg 275w" sizes="auto, (max-width: 455px) 100vw, 455px" /> Zurück zu den neuen Optionen. Lasse ich alle drei Haken gesetzt, dann verhält sich das System wie gewohnt. Ich sehe die Speichermöglichkeiten in der Requestpage und im Layout: <img loading="lazy" decoding="async" class="alignnone wp-image-378 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/07/Report6_3_Berichtsoptionen.jpg" alt="Report6_3_Berichtsoptionen" width="566" height="488" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/07/Report6_3_Berichtsoptionen.jpg 566w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/Report6_3_Berichtsoptionen-300x259.jpg 300w" sizes="auto, (max-width: 566px) 100vw, 566px" /> Setze ich allerdings die Haken „Enable Save as Excel on Request Pages of RDLC-layout Reports“ & „Enable Save as Word on Request Pages of RDLC-layout Reports“ nicht, so stehen mir die Möglichkeiten auch nicht in der Requestpage zur Verfügung. <img loading="lazy" decoding="async" class="alignnone wp-image-380 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/07/Report6_5_NewOptionsFalse.jpg" alt="Report6_5_NewOptionsFalse" width="1126" height="430" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/07/Report6_5_NewOptionsFalse.jpg 1126w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/Report6_5_NewOptionsFalse-300x115.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/Report6_5_NewOptionsFalse-768x293.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/Report6_5_NewOptionsFalse-1024x391.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/Report6_5_NewOptionsFalse-665x254.jpg 665w" sizes="auto, (max-width: 1126px) 100vw, 1126px" /> <img loading="lazy" decoding="async" class="alignnone wp-image-381 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/07/Report6_6_Berichtsoptionen2.jpg" alt="Report6_6_Berichtsoptionen2" width="567" height="443" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/07/Report6_6_Berichtsoptionen2.jpg 567w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/Report6_6_Berichtsoptionen2-300x234.jpg 300w" sizes="auto, (max-width: 567px) 100vw, 567px" /> Wenn ich den Bericht aber in der Vorschau starte, dann kann ich den Bericht trotzdem als Excel oder Word exportieren. Das bedeutet im Umkehrschluss: Entweder ich setze alle drei Haken oder ich entferne alle drei Haken. Sind alle drei Haken entfernt, dann steht mir das „Speichern“ aus der PreView auch nicht mehr zur Verfügung. Die eigentliche Problematik ist eine Andere. Ich kann nicht entscheiden, ob ich diese Funktionen beispielsweise bei der Rechnung deaktivieren möchte. Vielleicht möchte ich bei einer Kreditor/Artikel Statistik zulassen, dass dieser Bericht einschließlich der Werte nach Excel exportiert werden darf und bei einer Verkaufsrechnung eben nicht. Zusätzlich möchte ich auch pro Bericht entscheiden, ob ein Export per Word, Excel oder PDF in der Vorschau zulässig ist. Bei einer Verkaufsrechnung wird nämlich „Anzahl gedruckt“ nur hochgezählt, wenn es nicht in der Vorschau aufgerufen wird. Das ist für mich einer der Hauptgründe, warum Microsoft dort etwas tun sollte. Ich persönlich kann mit diesem Feature nicht so wirklich etwas anfangen. Klar es gibt vielleicht Einsatzgebiete wo das Sinn machen könnte. Nehmen wir beispielsweise an, dass wir eine eigene Service Tier für das Lager haben und dort möchte ich auch verhindern, dass irgendwer Daten kopierbar aus dem System exportiert. Dann könnte ich diese Optionen bei dieser spezifischen Service Tier deaktivieren. In meinen Projekten bin ich aber nie auf eine solche Anforderung gestoßen. Vielmehr wünscht man sich die berichtsabhängige Einstellung einer solchen Einschränkung. Wer das genauso sieht und sich eine Option pro Bericht wünscht, der kann hier dafür voten (MS Connect – Enable or Disable Word/Excel/PDF/PreView per Report). Wenn genug Leute voten, dann kann es sein, dass Microsoft sich das für eine der Folgeversionen zu Herzen nimmt. Ich wünsche mir, dass man dafür eine gute Lösung implementiert (ähnlich wie die Funktion PDFFontEmbedding). Wer das MS Connect nicht kennt, der sollte wissen, dass dies eine Plattform ist, wo „NAV Anwender, Entwickler, Partner, …“ Produktwünsche melden können. In regelmäßigen Abständen werden diese Vorschläge dann von Microsoft bewertet und evtl. auch umgesetzt. Für Fragen oder Feedback schreibt mir doch einfach einen Kommentar! The post Dynamics NAV 2016 – CU9 – Server Konfiguration RDLC Bericht – Word / Excel Export first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Hallo Leute, ich werde immer wieder gefragt, wie man mit Dateien im RTC umgeht! Es haben sich im Gegensatz zum Classic Client einige Dinge geändert. Vieles davon hat sicherlich schon die Runde gemacht und einige Dinge sind evtl. auch noch neu für Euch. Heute möchte ich kurz erläutern, wie man mit Dateien ab NAV 2009… Weiterlesen » The post Dynamics NAV – Datei Import/Export #1 first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Hallo Leute, ich werde immer wieder gefragt, wie man mit Dateien im RTC umgeht! Es haben sich im Gegensatz zum Classic Client einige Dinge geändert. Vieles davon hat sicherlich schon die Runde gemacht und einige Dinge sind evtl. auch noch neu für Euch. Heute möchte ich kurz erläutern, wie man mit Dateien ab NAV 2009 RTC umgeht und wie man idealerweise eine solide Grundstruktur für automatische Verarbeitungen oder auch für manuelle Verarbeitungen von Dateien schafft. Ich werde das exemplarisch mit NAV 2016 zeigen. Einige Funktionen sind in NAV 2009 evtl. noch nicht vorhanden, aber das Prinzip ist gleich. Zu aller erst möchte ich daher auf einen wichtigen Punkt hinweisen. Microsoft liefert mit der Codeunit 419 „File Management“ schon eine super Auswahl an vielen Funktion aus, die wir ohne Probleme nutzen können. Auch müssen wir berücksichtigen, dass der C/AL Code in der Regel immer auf der Service Tier ausgeführt wird. Klar kann man beispielsweise .NET Komponenten dazu zwingen auch auf dem Client zu laufen, aber das ist der grundlegende Punkt. Wenn ihr versucht eine Datei mit einer Variable vom Datentyp „File“ auf Laufwerk C:\ zu öffnen, dann wird dieser Code auf der Service Tier ausgeführt und dort wird nach der Datei auf Laufwerk C:\ gesucht. Daher muss man sich hier anders behelfen. Schritt 1: Dafür erstelle ich nun exemplarisch einen neuen Bericht (R50004) und nenne diesen „Import File“. Des Weiteren stelle ich ProcessingOnly auf Yes, da ich keine Seitenansicht benötige und somit einen „OK“ Knopf zum ausführen des Berichtes bekomme. <img loading="lazy" decoding="async" class="alignnone wp-image-310 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_1_NewReport.jpg" alt="DateiHandling_1_NewReport" width="940" height="489" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_1_NewReport.jpg 1032w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_1_NewReport-300x156.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_1_NewReport-768x400.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_1_NewReport-1024x533.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_1_NewReport-660x343.jpg 660w" sizes="auto, (max-width: 940px) 100vw, 940px" /> Schritt 2: Ich lege globale Variablen an, um die Datei clientseitig und serverseitig verarbeiten zu können. FileManagment CU419 -> Nutzen der im Standard gelieferten Funktionen FileName -> Stellt den Dateinamen inkl. Pfad auf dem Client dar ServerFileName -> Stellt den Dateinamen inkl. Pfad auf dem Server dar <img loading="lazy" decoding="async" class="alignnone wp-image-311 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_2_NewVariable.jpg" alt="DateiHandling_2_NewVariable" width="540" height="352" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_2_NewVariable.jpg 540w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_2_NewVariable-300x196.jpg 300w" sizes="auto, (max-width: 540px) 100vw, 540px" /> Schritt 3: Erstellung Requestpage, sodass der Anwender eine Client auswählen kann. Dafür erstelle ich eine „ContentArea“ eine Gruppe „Optionen“ und hinterlege das Feld „FileName“. <img loading="lazy" decoding="async" class="alignnone wp-image-312 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_3_RequestPage.jpg" alt="DateiHandling_3_RequestPage" width="804" height="279" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_3_RequestPage.jpg 804w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_3_RequestPage-300x104.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_3_RequestPage-768x267.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_3_RequestPage-660x229.jpg 660w" sizes="auto, (max-width: 804px) 100vw, 804px" /> Schritt 4: Zusätzlich lege ich nun zwei Textkonstanten an. Diese benötige ich gleich für den Aufruf der Funktion „OpenFileDialog“: ImportFileCaption – DEU=Importiere Datei;ENU=Import File TxtFilterString -DEU=Textdateien (*.txt)|*.txt;ENU=Text Files (*.txt)|*.txt <img loading="lazy" decoding="async" class="alignnone wp-image-313 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_4_OpenFileDialogTextKonstants.jpg" alt="DateiHandling_4_OpenFileDialogTextKonstants" width="685" height="365" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_4_OpenFileDialogTextKonstants.jpg 685w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_4_OpenFileDialogTextKonstants-300x160.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_4_OpenFileDialogTextKonstants-660x352.jpg 660w" sizes="auto, (max-width: 685px) 100vw, 685px" /> Schritt 5: Im OnAssistEdit rufe ich nun die Funktion „OpenFileDialog“ aus dem FileManagement auf. Diese hat drei Parameter: „WindowTitle“: Wie soll das Fenster heißen. Hier könnte man beispielsweise auch „Importiere Preisliste“ oder „Datei für Preislistenimport auswählen“ hinterlegen. Wichtig ist dabei nur, dass man einen Titel wählt, der zu dem Import passt. In meinem Fall verwende ich hier die Textkonstante: „ImportFileCaption“ „DefaultFileName“: Gibt den Standardpfad und/oder den Dateinamen an. Ich hinterlege hier nichts, da ich in meinem Fall nichts vorbelegen möchte. „FilterString“: Hier kann man angeben, welche Dateitypen überhaupt ausgewählt werden dürfen. In meinem Beispiel verwende ich die Textkonstante TxtFilterString. Hierbei trägt man die Beschreibung und dann getrennt mit einem „Pipe“ (|) die Dateiendung, die man zulassen möchte (siehe mein Beispiel). Vorsicht. Auch im Validatetrigger des Feldes sollte geprüft werden, ob die Datei die richtige Endung hat. <img loading="lazy" decoding="async" class="alignnone wp-image-314 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_5_OpenFileDialog.jpg" alt="DateiHandling_5_OpenFileDialog" width="725" height="248" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_5_OpenFileDialog.jpg 725w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_5_OpenFileDialog-300x103.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_5_OpenFileDialog-660x226.jpg 660w" sizes="auto, (max-width: 725px) 100vw, 725px" /> Schritt 6: Testen des Berichts – Führe ich den Bericht aus, öffnet sich die RequestPage, in der ich eine Datei, im Feld „Dateiname“ hinterlegen kann. Drücke ich auf die drei Pünktchen, dann öffnet sich der File Dialog. Hier sieht man nun auch, wie mein Filterstring und mein Fenstertitel greifen. <img loading="lazy" decoding="async" class="alignnone wp-image-315 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_6_Berichtsausgabe.jpg" alt="DateiHandling_6_Berichtsausgabe" width="416" height="357" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_6_Berichtsausgabe.jpg 416w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_6_Berichtsausgabe-300x257.jpg 300w" sizes="auto, (max-width: 416px) 100vw, 416px" /> <img loading="lazy" decoding="async" class="alignnone wp-image-316 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_7_Berichtsausgabe_AssistEdit.jpg" alt="DateiHandling_7_Berichtsausgabe_AssistEdit" width="786" height="480" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_7_Berichtsausgabe_AssistEdit.jpg 786w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_7_Berichtsausgabe_AssistEdit-300x183.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_7_Berichtsausgabe_AssistEdit-768x469.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_7_Berichtsausgabe_AssistEdit-660x403.jpg 660w" sizes="auto, (max-width: 786px) 100vw, 786px" /> Schritt 7: Nun müssen wir noch ein wenig Programmcode hinzufügen, um die Datei auch hochzuladen (auf die NST) und die Prüfung auf die Dateiendung integrieren: Ich füge nun also zwei Funktionen „GetFileEnding“ und „UploadFile“ hinzu: GetFileEnding ermittelt die Dateiendung und gibt diese zurück. UploadFile prüft die Dateiendung und lädt die Datei auf dem Server hoch: <img loading="lazy" decoding="async" class="alignnone wp-image-318 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_8_Zusatzfunktionen.jpg" alt="DateiHandling_8_Zusatzfunktionen" width="738" height="499" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_8_Zusatzfunktionen.jpg 738w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_8_Zusatzfunktionen-300x203.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_8_Zusatzfunktionen-660x446.jpg 660w" sizes="auto, (max-width: 738px) 100vw, 738px" /> Schritt 8: Die Funktionen müssen wir nun noch im OnValidate und im OnAssistEdit des Feldes „FileName“ integrieren: <img loading="lazy" decoding="async" class="alignnone size-full wp-image-319" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_9_DateinameValidate_Assist.jpg" alt="DateiHandling_9_DateinameValidate_Assist" width="810" height="230" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_9_DateinameValidate_Assist.jpg 810w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_9_DateinameValidate_Assist-300x85.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_9_DateinameValidate_Assist-768x218.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_9_DateinameValidate_Assist-660x187.jpg 660w" sizes="auto, (max-width: 810px) 100vw, 810px" /> Schritt 9: Zu guter letzt können wir nun noch prüfen, ob unser Programmcode funktioniert. Dafür prüfe ich mit „EXISTS“, ob die Datei auf dem Server gefunden werden kann. EXISTS wird nämlich auf dem Server ausgeführt: <img loading="lazy" decoding="async" class="alignnone wp-image-320 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_10_OnPreReport.jpg" alt="DateiHandling_10_OnPreReport" width="337" height="113" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_10_OnPreReport.jpg 337w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_10_OnPreReport-300x101.jpg 300w" sizes="auto, (max-width: 337px) 100vw, 337px" /> Schritt 10: Nun den Bericht zum Test einmal ausführen: <img loading="lazy" decoding="async" class="alignnone wp-image-321 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_11_Test.jpg" alt="DateiHandling_11_Test" width="416" height="360" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_11_Test.jpg 416w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_11_Test-300x260.jpg 300w" sizes="auto, (max-width: 416px) 100vw, 416px" /> <img loading="lazy" decoding="async" class="alignnone wp-image-322 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_12_TestMessage.jpg" alt="DateiHandling_12_TestMessage" width="324" height="131" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_12_TestMessage.jpg 324w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_12_TestMessage-300x121.jpg 300w" sizes="auto, (max-width: 324px) 100vw, 324px" /> Der Benutzer kann über den AssistEdit Knopf keine falsche Datei auswählen. Versucht der Anwender eine nicht unterstützte Datei direkt in den Dateinamen zu kopieren, wird dies über unsere kleine Prüfung verhindert: <img loading="lazy" decoding="async" class="alignnone wp-image-357 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_13_PrüfungAufEndung.jpg.jpg" alt="DateiHandling_13_PrüfungAufEndung.jpg" width="433" height="439" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_13_PrüfungAufEndung.jpg.jpg 433w, https://robert-dynamicsnav.de/wp-content/uploads/2016/07/DateiHandling_13_PrüfungAufEndung.jpg-296x300.jpg 296w" sizes="auto, (max-width: 433px) 100vw, 433px" /> Hier findet ihr den Bericht, wie immer als txt oder als fob: 160704_ImportFile.zip Für Fragen hinterlasst mir einfach einen Kommentar. In folgenden Beiträgen werde ich mich mit dem Import Excel Dateien, CSV Dateien und anderen Besonderheiten auseinandersetzen. The post Dynamics NAV – Datei Import/Export #1 first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
SOAP Web Services konsumieren mit Dynamics NAV
Hey Leute, heute möchte ich meine Erfahrungen mit der Anbindung von externen Web Services an Dynamics NAV teilen. Dabei muss man grundsätzlich sagen, dass es zwei Formen von Web Services gibt. Zum Einen gibt es SOAP Web Services und zum Anderen gibt es REST Web Services. Den Unterschied zwischen REST und SOAP kann man hier… Weiterlesen » The post SOAP Web Services konsumieren mit Dynamics NAV first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Hey Leute, heute möchte ich meine Erfahrungen mit der Anbindung von externen Web Services an Dynamics NAV teilen. Dabei muss man grundsätzlich sagen, dass es zwei Formen von Web Services gibt. Zum Einen gibt es SOAP Web Services und zum Anderen gibt es REST Web Services. Den Unterschied zwischen REST und SOAP kann man hier nachlesen: SOAP vs REST Wenn Ihr REST Web Services konsumieren möchtet, dann kann ich nur die Serie von „Kauffmann“ empfehlen. Hier wird erklärt, wie man das macht: NAV Techdays 2015 – The Web Service Examples Web Services Examples Part 1 – The Basic Pattern Web Services Examples Part 2 – Verify E-mail Address Web Services Examples Part 3 – Generate Barcode Web Services Example Part 4 – Send SMS text message Web Services Example Part 5 – DocuSign Integration Web Services Example 6 – Office 365 Inbox Web Services Example 7 – Call NAV OData Web Services (Part 1) Im Bereich SOAP gibt es auch ein paar Beiträge von Vjeko: Web Services Black Belt: consuming NAV web services using pure C/AL Hier geht es allerdings um Dynamics NAV Web Services, die durch C/AL konsumiert werden. Wenn man aber nun einen fremden Web Services in Dynamics NAV konsumieren möchte, ist C/AL wohl die falsche Wahl. Zu mindestens trifft das auf mich zu. Ich möchte heute erläutern, wie man einen Web Services mit einer selbst entwickelten Klassenbibliothek konsumieren kann. Das bedeutet ich werde heute erläutern, wie man eine Klassenbibliothek mit C# in Visual Studio 2015 erstellt, diese dann in Dynamics NAV integriert und den Web Services dann aus NAV heraus konsumiert. Wir lagern also einen kleinen Teil der Business Logik aus und haben dennoch eine Integration in Dynamics NAV. Wer kein Visual Studio besitzt, kann evtl. die Visual Studio Community Edition nutzen Visual Studio CE. Dies ist mit gewissen Auflagen verbunden, bzw. nur bestimmte Personenkreise oder Firmen dürfen das kostenlos nutzen. Für unser heutiges Beispiel benötigen wir also einen Web Service. Jeder öffentliche Web Services kann dafür verwendet werden. Ich verwende für das Beispiel diesen SOAP Web Service: http://www.webservicex.net/geoipservice.asmx?WSDL Dieser Web Service gibt uns im Idealfall Informationen zu einer IP zurück. Ich werde exemplarisch zeigen, wie man von einer IP Adresse den Ländercode zurückbekommt. Dafür öffne ich zuerst Visual Studio und erstelle ein neues Projekt und eine neue Klassenbibliothek: 1.) Ist Visual Studio geöffnet über das Menüband ein neues Projekt erstellen: Datei -> Neu -> Projekt… <img loading="lazy" decoding="async" class="alignnone wp-image-249 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-1-Neues-Projekt.jpg" alt="Web Services - 1 Neues Projekt" width="803" height="161" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-1-Neues-Projekt.jpg 803w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-1-Neues-Projekt-300x60.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-1-Neues-Projekt-768x154.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-1-Neues-Projekt-660x132.jpg 660w" sizes="auto, (max-width: 803px) 100vw, 803px" /> 2.) Im Fenster „Neues Projekt“ folgendes tun: Visual C# -> Klassenbibliothek -> Name „SOAPWebServiceConnector“ <img loading="lazy" decoding="async" class="alignnone wp-image-250 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-2-Klassenbibliothek.jpg" alt="Web Services - 2 Klassenbibliothek" width="955" height="657" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-2-Klassenbibliothek.jpg 955w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-2-Klassenbibliothek-300x206.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-2-Klassenbibliothek-768x528.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-2-Klassenbibliothek-660x454.jpg 660w" sizes="auto, (max-width: 955px) 100vw, 955px" /> 3.) Ich benenne die Klasse von Class1 in SOAPWebServiveConnector um: Wichtig ist auch, dass die Klasse als „public“ gekennzeichnet ist. Ist dies nicht der Fall so haben wir nachher keinen Zugriff auf die Funktionen der Klasse. <img loading="lazy" decoding="async" class="alignnone wp-image-251 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-3-C-Shape-Projekt.jpg" alt="Web Services - 3 C Shape Projekt" width="1392" height="321" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-3-C-Shape-Projekt.jpg 1392w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-3-C-Shape-Projekt-300x69.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-3-C-Shape-Projekt-768x177.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-3-C-Shape-Projekt-1024x236.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-3-C-Shape-Projekt-660x152.jpg 660w" sizes="auto, (max-width: 1392px) 100vw, 1392px" /> Der Vorteil von Visual Studio ist ganz klar, dass ich hier eine Web Referenz hinterlegen kann. Damit ist es mir möglich schnell und effektiv auf alle Funktionen und Klassen eines Web Services zugreifen zu können. Dafür legen wir also eine neue Web Referenz an: 1.) Rechtsklick auf Verweise und die Aktion „Dienstverweis hinzufügen“ auswählen: <img loading="lazy" decoding="async" class="alignnone wp-image-252 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-4-Dienstverweis-hinzufügen.jpg" alt="Web Services - 4 Dienstverweis hinzufügen" width="389" height="304" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-4-Dienstverweis-hinzufügen.jpg 389w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-4-Dienstverweis-hinzufügen-300x234.jpg 300w" sizes="auto, (max-width: 389px) 100vw, 389px" /> 2.) Im Fenster „Dienstverweis hinzufügen“ auf „Erweitert…“ klicken: <img loading="lazy" decoding="async" class="alignnone wp-image-253 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-5-Dienstverweis-hinzufügen_2.jpg" alt="Web Services - 5 Dienstverweis hinzufügen_2" width="628" height="514" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-5-Dienstverweis-hinzufügen_2.jpg 628w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-5-Dienstverweis-hinzufügen_2-300x246.jpg 300w" sizes="auto, (max-width: 628px) 100vw, 628px" /> 3.) In den Dienstverweiseinstellungen auf „Webverweis auswählen“ klicken: <img loading="lazy" decoding="async" class="alignnone wp-image-254 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-6-Dienstverweis-hinzufügen_3.jpg" alt="Web Services - 6 Dienstverweis hinzufügen_3" width="648" height="621" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-6-Dienstverweis-hinzufügen_3.jpg 648w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-6-Dienstverweis-hinzufügen_3-300x288.jpg 300w" sizes="auto, (max-width: 648px) 100vw, 648px" /> 4.) In der URL die gewünschte SOAP Web Adresse angeben. In meinem Fall ist das: „http://www.webservicex.net/geoipservice.asmx?WSDL“ und danach auf den kleinen Pfeil klicken. Nun wird die Web Service Definition importiert und gelesen. Wir hinterlegen zusätzlich einen Webverweisnamen „GeoIPWebService“ und klicken dann auch „Verweis hinzufügen“. <img loading="lazy" decoding="async" class="alignnone wp-image-255 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-7-Dienstverweis-hinzufügen_4.jpg" alt="Web Services - 7 Dienstverweis hinzufügen_4" width="826" height="574" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-7-Dienstverweis-hinzufügen_4.jpg 826w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-7-Dienstverweis-hinzufügen_4-300x208.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-7-Dienstverweis-hinzufügen_4-768x534.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-7-Dienstverweis-hinzufügen_4-660x459.jpg 660w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-7-Dienstverweis-hinzufügen_4-200x140.jpg 200w" sizes="auto, (max-width: 826px) 100vw, 826px" /> In unserer Klasse „SOAPWebServiceConnector“ schreiben wir nun ein paar Zeilen Programmcode. Ich lege hier eine öffentliche (von außen erreichbare) Methode GetCountryCodeByIP an. Dabei bedeutet public, dass dies keine interne Funktion ist (vergleichbar mit der Eigenschaft Local in Codeunitfunktionen). „string“ definiert den Datentyp des Rückgabewertes. Ich gebe also einen Text zurück! „GetCountryCodeByIP“ ist der Methodenname. „string IPAddress“ definiert die Parameter. In diesem Fall habe ich nur einen Parameter. Benötige ich mehrere Parameter, so trenne ich diese mit einem Komma. Möchte ich einen Paramter wieder zurück an den Aufruf der Methode geben, dann schreibe ich „ref“ vor den Datentyp. Innerhalb der Funktion muss ich nun eine Verbindung zu dem Web Service aufbauen und den Ländercode als „return value“ zurückgeben. Dafür definiere ich eine neue lokale Textvariable „CountryCode“ Ich rufe den Konstruktor des WebService auf. Damit stelle ich eine Verbindung her und kann mit der erstellten Variable auf die Funktionen des Web Services zugreifen. Mehr über Konstruktoren kann man hier lesen (https://msdn.microsoft.com/de-de/library/ace5hbzh.aspx) Ich rufe des Weiteren den Konstruktor der Klasse „GeoIP“ auf, da dieser als Rückgabewert der Web Service Funktion erwartet wird. Nun rufe ich die Funktion „GetGeoIP“ mit meinem Parameter auf. Die Klasse „GeoIP“ wird nun vom Web Service gefüllt. Anschließend schreibe ich das Feld „CountryCode“ aus der Klasse „GeoIP“ in die Variable „CountryCode“ und definiere den lokalen „CountryCode“ als Rückgabewert. <img loading="lazy" decoding="async" class="alignnone wp-image-256 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-8-Funktion-zum-Abruf-des-Web-Services.jpg" alt="Web Services - 8 Funktion zum Abruf des Web Services" width="847" height="459" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-8-Funktion-zum-Abruf-des-Web-Services.jpg 847w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-8-Funktion-zum-Abruf-des-Web-Services-300x163.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-8-Funktion-zum-Abruf-des-Web-Services-768x416.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-8-Funktion-zum-Abruf-des-Web-Services-660x358.jpg 660w" sizes="auto, (max-width: 847px) 100vw, 847px" /> Nun erstelle und veröffentliche ich meine DLL: 1.) Umstellen des Modus auf „Release“: <img loading="lazy" decoding="async" class="alignnone wp-image-257 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-9-DLL-erstellen.jpg" alt="Web Services - 9 DLL erstellen" width="805" height="87" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-9-DLL-erstellen.jpg 805w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-9-DLL-erstellen-300x32.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-9-DLL-erstellen-768x83.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-9-DLL-erstellen-660x71.jpg 660w" sizes="auto, (max-width: 805px) 100vw, 805px" /> 2.) Über das Menüband „Erstellen“ -> „SOAPWebServiceConnector neu erstellen“ auswählen. <img loading="lazy" decoding="async" class="alignnone wp-image-258 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-10-DLL-erstellen_2.jpg" alt="Web Services - 10 DLL erstellen_2" width="645" height="278" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-10-DLL-erstellen_2.jpg 645w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-10-DLL-erstellen_2-300x129.jpg 300w" sizes="auto, (max-width: 645px) 100vw, 645px" /> 3.) Den Projektordner öffnen und die kompilierten Dateien finden: <img loading="lazy" decoding="async" class="alignnone wp-image-259 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-11-DLL-erstellen_3.jpg" alt="Web Services - 11 DLL erstellen_3" width="941" height="310" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-11-DLL-erstellen_3.jpg 941w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-11-DLL-erstellen_3-300x99.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-11-DLL-erstellen_3-768x253.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-11-DLL-erstellen_3-660x217.jpg 660w" sizes="auto, (max-width: 941px) 100vw, 941px" /> 4.) Je nachdem ob das Addin/Klassenbibliothek Clientseitig (RunOnClient) läuft oder Serverseitig entsprechend im Server/Clientverzeichnis ablegen. In meinem Beispiel muss es im Serververzeichnis abgelegt werden. Benötigt wird lediglich die Datei „SOAPWebServiceConnector.dll“. <img loading="lazy" decoding="async" class="alignnone wp-image-260 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-12-Addin-ablegen.jpg" alt="Web Services - 12 Addin ablegen" width="881" height="740" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-12-Addin-ablegen.jpg 881w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-12-Addin-ablegen-300x252.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-12-Addin-ablegen-768x645.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-12-Addin-ablegen-660x554.jpg 660w" sizes="auto, (max-width: 881px) 100vw, 881px" /> <img loading="lazy" decoding="async" class="alignnone wp-image-261 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-13-Addin-ablegen_2.jpg" alt="Web Services - 13 Addin ablegen_2" width="790" height="374" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-13-Addin-ablegen_2.jpg 790w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-13-Addin-ablegen_2-300x142.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-13-Addin-ablegen_2-768x364.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-13-Addin-ablegen_2-660x312.jpg 660w" sizes="auto, (max-width: 790px) 100vw, 790px" /> Nun ist das Addin / unsere Klassenbibliothek in Dynamics NAV verfügbar. Ich öffne den Entwicklungsclient erstelle eine neue Codeunit und integriere meine Klassenbibliothek. <img loading="lazy" decoding="async" class="alignnone wp-image-262 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-14-Neue-Codeunit.jpg" alt="Web Services - 14 Neue Codeunit" width="1481" height="700" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-14-Neue-Codeunit.jpg 1481w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-14-Neue-Codeunit-300x142.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-14-Neue-Codeunit-768x363.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-14-Neue-Codeunit-1024x484.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-14-Neue-Codeunit-660x312.jpg 660w" sizes="auto, (max-width: 1481px) 100vw, 1481px" /> Ich erstelle hier eine Funktion „GetCountryCodeOfIPAddress und greife damit auf meinen Web Service zu. Ich übergebe eine IP-Adresse und lasse mir am Ende der Funktion per Nachricht den Ländercode zurückgeben. Auch in C/AL muss der Konstruktor einer .NET Klasse aufgerufen werden, damit wir auf die Funktionen der Klasse zugreifen können. <img loading="lazy" decoding="async" class="alignnone wp-image-263 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-15-Codeunit-Eigenschaften.jpg" alt="Web Services - 15 Codeunit Eigenschaften" width="822" height="512" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-15-Codeunit-Eigenschaften.jpg 822w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-15-Codeunit-Eigenschaften-300x187.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-15-Codeunit-Eigenschaften-768x478.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-15-Codeunit-Eigenschaften-660x411.jpg 660w" sizes="auto, (max-width: 822px) 100vw, 822px" /> Um die .NET Variable zu definieren, einfach folgende Schritte ausführen: Die lokalen Variablen der Funktion öffnen Als DataType „DotNet“ auswählen. Beim Subtype abtauchen. Unter dem Register Dynamics NAV unseren SOAPWebServiceConnector suchen. Anschließend unsere Klasse „SOAPWebServiceConnector“ auswählen. Mit „OK“ bestätigen. <img loading="lazy" decoding="async" class="alignnone wp-image-264 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-16-Dotnet-Variable.jpg" alt="Web Services - 16 Dotnet Variable" width="1409" height="669" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-16-Dotnet-Variable.jpg 1409w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-16-Dotnet-Variable-300x142.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-16-Dotnet-Variable-768x365.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-16-Dotnet-Variable-1024x486.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-16-Dotnet-Variable-660x313.jpg 660w" sizes="auto, (max-width: 1409px) 100vw, 1409px" /> Zu guter letzt einfach einen Bericht erstellen, der unsere C/AL Funktion aufruft: <img loading="lazy" decoding="async" class="alignnone wp-image-265 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-17-Execute-Web-Service.jpg" alt="Web Services - 17 Execute Web Service" width="1161" height="549" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-17-Execute-Web-Service.jpg 1161w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-17-Execute-Web-Service-300x142.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-17-Execute-Web-Service-768x363.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-17-Execute-Web-Service-1024x484.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-17-Execute-Web-Service-660x312.jpg 660w" sizes="auto, (max-width: 1161px) 100vw, 1161px" /> <img loading="lazy" decoding="async" class="alignnone wp-image-266 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-18-Execute-Web-Service_2.jpg" alt="Web Services - 18 Execute Web Service_2" width="379" height="335" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-18-Execute-Web-Service_2.jpg 379w, https://robert-dynamicsnav.de/wp-content/uploads/2016/05/Web-Services-18-Execute-Web-Service_2-300x265.jpg 300w" sizes="auto, (max-width: 379px) 100vw, 379px" /> Ich bin kein C# oder .NET Programmierer, aber wer hätte gedacht, dass es so einfach ist einen externen SOAP Web Service zu konsumieren. Für mich ist das der leichteste Weg um einen Web Service zu konsumieren. Sicherlich gibt es hier auch noch andere Wege, aber das gibt Euch sicherlich ein paar Ideen, wie man die Anbindung verschiedener Systeme lösen kann. Hier gibt es wie gewohnt die NAV Objekte und das Visual Studio Projekt: 160507_ConsumeSOAPWebServiceInNAV.zip SOAPWebServiceConnector.zip The post SOAP Web Services konsumieren mit Dynamics NAV first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
RDLC für NAV Entwickler #5 – RDLC Belegdesign – Grundlagen & unterschiedliche Kopfgrößen
Hey Leute, nachdem wir uns mit den Einstiegs-Themen zum Thema RDLC beschäftigt haben: RDLC für NAV Entwickler #1 – Allgemeine Informationen & das Dataset RDLC für NAV Entwickler #2 – Grundlagen des Layouts – Teil 1 „Der Kopf“ RDLC für NAV Entwickler #3 – Grundlagen des Layouts – Teil 2 „Der Textkörper“ RDLC für NAV Entwickler… Weiterlesen » The post RDLC für NAV Entwickler #5 – RDLC Belegdesign – Grundlagen & unterschiedliche Kopfgrößen first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Hey Leute, nachdem wir uns mit den Einstiegs-Themen zum Thema RDLC beschäftigt haben: RDLC für NAV Entwickler #1 – Allgemeine Informationen & das Dataset RDLC für NAV Entwickler #2 – Grundlagen des Layouts – Teil 1 „Der Kopf“ RDLC für NAV Entwickler #3 – Grundlagen des Layouts – Teil 2 „Der Textkörper“ RDLC für NAV Entwickler #4 – Kopieren von Berichten / Layouts möchte ich nun auf Belegdesign eingehen und wie Belege aus meinen Erfahrungen gestaltet werden müssen. Dabei meine ich mit Belegen, alle Berichte, die eine Kopf-/Zeilenstruktur besitzen. Beispiele sind Einkaufs- und Verkaufsbelege (Verkaufsrechnung, Einkaufsbestellung, …). In meinen heutigen Beispiel gehe ich daher auf ein paar Grundlagen ein und zeige wie man unterschiedliche Kopfgrößen in RDLC realisieren kann! Ich werde auf verschiedene Dinge eingehen, allerdings keine kompletten Belege zur Verfügung stellen. Wenn ich also nicht auf den CopyLoop eingehe oder andere Dinge (Mehrsprachigkeit, unterschiedliche Währungen, Übertragen von Textkonstanten) eingehe, dann bitte ich dies zu entschuldigen. Falls es dort Bedarf gibt, lasst es mich wissen, dann schauen wir uns das noch in einem späteren Beitrag an. Zu allererst benötigen wir eine Ausgangsbasis. Dafür habe ich einen neuen Bericht erstellt und ein grundlegendes Dataset erstellt. <img loading="lazy" decoding="async" class="alignnone wp-image-222 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_1_Dataset_CompInfo.jpg" alt="RDLC5_1_Dataset_CompInfo" width="550" height="489" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_1_Dataset_CompInfo.jpg 824w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_1_Dataset_CompInfo-300x267.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_1_Dataset_CompInfo-768x683.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_1_Dataset_CompInfo-660x587.jpg 660w" sizes="auto, (max-width: 550px) 100vw, 550px" /> Wichtig ist hierbei, dass ich das Bild in einem separaten DataItem übergebe. Das mache ich natürlich aus einem bestimmten Grund: Das Bild ist normalerweise auf jedem Ausdruck gleich. Würde ich es im „Sales Invoice Header“ an das Dataset übergeben, dann sorge ich für ein stark vergrößertes Dataset. Das kann im schlimmsten Fall zu einer „OutofMemoryException“ führen. Daher immer dafür sorgen, dass das Bild nur einmal übergeben wird! Da die Firmendaten und der Sales Invoice Header auf der ersten Ebene sind, funktioniert der „SETTABLEVIEW“-Befehl für den Bericht immer noch. Es hat also keine Nachteile. In Visual Studio müssen wir dann aber auch berücksichtigen, dass wir diesen ersten Eintrag im Dataset „wegfiltern“. Darüber hinaus gibt es von Microsoft selbst auch ein paar Tipps zur Performance (blogs.msdn.microsoft.com – RDLC Performance Optimization Tips). Sollte man beim Erstellen und Testen von Berichten auf leere Seiten stoßen, dann kann ich nur diesen Blog von Natalie empfehlen: nataliesnav.de – Leere Seiten im NAV Report Des Weiteren habe ich folgenden Code eingefügt: <img loading="lazy" decoding="async" class="alignnone wp-image-223 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_2_Code.jpg" alt="RDLC5_2_Code" width="515" height="402" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_2_Code.jpg 845w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_2_Code-300x234.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_2_Code-768x599.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_2_Code-660x515.jpg 660w" sizes="auto, (max-width: 515px) 100vw, 515px" /> mit folgenden Variablen: <img loading="lazy" decoding="async" class="alignnone wp-image-224 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_3_Variablen.jpg" alt="RDLC5_3_Variablen" width="457" height="243" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_3_Variablen.jpg 620w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_3_Variablen-300x160.jpg 300w" sizes="auto, (max-width: 457px) 100vw, 457px" /> Mehr brauchen wir im ersten Schritt nicht. Nun werde ich Schritt für Schritt erläutern, wie das Layout aufgebaut werden muss. In Visual Studio stelle ich natürlich wieder das Format auf A4 Hochformat und auf Zentimeter: <img loading="lazy" decoding="async" class="alignnone wp-image-225 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_4_Berichtseigenschaft.jpg" alt="RDLC5_4_Berichtseigenschaft" width="487" height="356" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_4_Berichtseigenschaft.jpg 766w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_4_Berichtseigenschaft-300x219.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_4_Berichtseigenschaft-660x483.jpg 660w" sizes="auto, (max-width: 487px) 100vw, 487px" /> Wenn wir uns nun den Kopf eines Berichtes anschauen, dann müssen wir folgendes akzeptieren. Die Kopfgröße ist immer statisch. Es gibt keine Möglichkeit diese Größe flexibel zu gestalten. Habe ich nun einen Kopf, der 5 cm hoch ist, dann kann ich das auf der nächsten Seite nicht verkleinern: <img loading="lazy" decoding="async" class="alignnone wp-image-226 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_5_Kopfhöhe.jpg" alt="RDLC5_5_Kopfhöhe" width="494" height="312" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_5_Kopfhöhe.jpg 676w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_5_Kopfhöhe-300x189.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_5_Kopfhöhe-660x417.jpg 660w" sizes="auto, (max-width: 494px) 100vw, 494px" /> Wir sollten also nicht versuchen, dieses Verhalten zu verändern, da es technisch nicht möglich ist. Aber was ist mit der folgenden Idee? Warum nicht den Kopf im RDL so gestalten, wie er auf der zweiten, dritten, vierten Seite sein soll. Ich kann doch auch den Textkörper für den großen Kopf der ersten Seite benutzen. Die große Frage ist nun, wie soll das Ganze funktionieren? Das werde ich nun Schritt für Schritt erläutern. <img loading="lazy" decoding="async" class="alignnone wp-image-228 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_6_KopfimTextkörper.jpg" alt="RDLC5_6_KopfimTextkörper" width="527" height="324" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_6_KopfimTextkörper.jpg 715w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_6_KopfimTextkörper-300x185.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_6_KopfimTextkörper-660x406.jpg 660w" sizes="auto, (max-width: 527px) 100vw, 527px" /> Einfügen einer Liste in den Textkörper. Eine Liste dient uns als Tabelle und gleichzeitig ein Rechteck. Der große Vorteil? Ich kann einen Seitenumbruch pro Beleg generieren und kann in meinem Rechteck alles platzieren, was auf einem Beleg gedruckt werden soll. Dafür erstellen wir also eine Liste, gruppieren nach der Nummer des Sales Invoice Header und erzeugen einen Seitenumbruch, wenn sich das Gruppenmerkmal „No.“ ändert. <img loading="lazy" decoding="async" class="alignnone wp-image-227 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_7_ListeDokument.jpg" alt="RDLC5_7_ListeDokument" width="969" height="468" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_7_ListeDokument.jpg 1615w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_7_ListeDokument-300x145.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_7_ListeDokument-768x371.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_7_ListeDokument-1024x495.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_7_ListeDokument-660x319.jpg 660w" sizes="auto, (max-width: 969px) 100vw, 969px" /> <img loading="lazy" decoding="async" class="alignnone wp-image-229 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_8_ListeGruppierung.jpg" alt="RDLC5_8_ListeGruppierung" width="622" height="392" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_8_ListeGruppierung.jpg 879w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_8_ListeGruppierung-300x189.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_8_ListeGruppierung-768x484.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_8_ListeGruppierung-660x416.jpg 660w" sizes="auto, (max-width: 622px) 100vw, 622px" /> <img loading="lazy" decoding="async" class="alignnone wp-image-230 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_9_Seitenumbruch.jpg" alt="RDLC5_9_Seitenumbruch" width="524" height="424" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_9_Seitenumbruch.jpg 679w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_9_Seitenumbruch-300x243.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_9_Seitenumbruch-660x535.jpg 660w" sizes="auto, (max-width: 524px) 100vw, 524px" /> Zusätzlich setze ich die Seitennummer in RDL zurück, wenn sich der Beleg ändert und setze einen Filter auf die „No.“ damit der erste Datensatz ausgeblendet wird. <img loading="lazy" decoding="async" class="alignnone wp-image-232 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_10_ZurücksetzenSeitennr2.jpg" alt="RDLC5_10_ZurücksetzenSeitennr2" width="964" height="550" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_10_ZurücksetzenSeitennr2.jpg 1313w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_10_ZurücksetzenSeitennr2-300x171.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_10_ZurücksetzenSeitennr2-768x438.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_10_ZurücksetzenSeitennr2-1024x584.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_10_ZurücksetzenSeitennr2-660x376.jpg 660w" sizes="auto, (max-width: 964px) 100vw, 964px" /> <img loading="lazy" decoding="async" class="alignnone wp-image-235 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_9_2_Filter.jpg" alt="RDLC5_9_2_Filter" width="498" height="531" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_9_2_Filter.jpg 687w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_9_2_Filter-281x300.jpg 281w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_9_2_Filter-660x704.jpg 660w" sizes="auto, (max-width: 498px) 100vw, 498px" /> Nun erstelle ich einfach einfach einen Kopf für die erste Seite und für die zweite Seite. Alles was auf der ersten Seite nicht in den Kopf passt, packen wir dann in Textkörper. Dafür benutze ich auch SetData / GetData. Diese Funktionen werden benötigt um Daten pro Beleg im Stapeldruck an den Kopf zu übergeben (Im Kopf kann man nämlich nur auf den ersten oder den letzten Eintrag im Dataset zugreifen). Das kann man auch hier nachlesen: SetData / GetData – Why it’s required? und hier: MSDN – SetData / GetData In dem ersten Beitrag zu SetData/GetData sollte man aber die Geschichte mit der VB Funktion „GetGroupPageNumber“ vergessen. Mit Dynamics NAV 2013 R2 ist das Feature „ResetPageNumber“ (s.o.) verfügbar und man braucht keinen extra Code dafür. Ich benutze die SetData/GetData-Funktionen aus dem MSDN mit einer kleinen Änderung. Wichtig ist meiner Meinung nach dabei, dass man die Aufrufe in die Hidden-Eigenschaft packt und das SetData immer True als Return Value zurückgibt. So sieht dann mein Kopfbereich aus: <img loading="lazy" decoding="async" class="alignnone wp-image-233" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_11_Köpfe_Sichtbarkeiten.jpg" alt="RDLC5_11_Köpfe_Sichtbarkeiten" width="929" height="511" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_11_Köpfe_Sichtbarkeiten.jpg 1154w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_11_Köpfe_Sichtbarkeiten-300x165.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_11_Köpfe_Sichtbarkeiten-768x423.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_11_Köpfe_Sichtbarkeiten-1024x563.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_11_Köpfe_Sichtbarkeiten-660x363.jpg 660w" sizes="auto, (max-width: 929px) 100vw, 929px" /> Ich habe also zwei Rechtecke und habe dort das Bild platziert (erst mal ohne flexible Positionierung) und mit einigen Werten. Ebenfalls blende ich das jeweilige Rechteck je nach der Seitennummer ein. Als Folgeschritt erstelle ich nun den zweiten Teil meines Kopfs auf der ersten Seite im Textkörper. <img loading="lazy" decoding="async" class="alignnone wp-image-234" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_12_KopfImTextköprerBeispiel.jpg" alt="RDLC5_12_KopfImTextköprerBeispiel" width="786" height="555" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_12_KopfImTextköprerBeispiel.jpg 1075w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_12_KopfImTextköprerBeispiel-300x212.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_12_KopfImTextköprerBeispiel-768x542.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_12_KopfImTextköprerBeispiel-1024x723.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_12_KopfImTextköprerBeispiel-660x466.jpg 660w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_12_KopfImTextköprerBeispiel-200x140.jpg 200w" sizes="auto, (max-width: 786px) 100vw, 786px" /> Ich packe noch ein paar Zeilen dazu und sorge für große Platzhalter um eine zweite Seite zu erzwingen: <img loading="lazy" decoding="async" class="alignnone wp-image-236" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_13_Zeilen.jpg" alt="RDLC5_13_Zeilen" width="535" height="581" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_13_Zeilen.jpg 710w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_13_Zeilen-276x300.jpg 276w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_13_Zeilen-660x717.jpg 660w" sizes="auto, (max-width: 535px) 100vw, 535px" /> Das Ergebnis sieht dann so aus: Seite 1 <img loading="lazy" decoding="async" class="alignnone wp-image-237" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_14_KopfSeite1.jpg" alt="RDLC5_14_KopfSeite1" width="651" height="454" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_14_KopfSeite1.jpg 855w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_14_KopfSeite1-300x209.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_14_KopfSeite1-768x535.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_14_KopfSeite1-660x460.jpg 660w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_14_KopfSeite1-200x140.jpg 200w" sizes="auto, (max-width: 651px) 100vw, 651px" /> Seite 2 <img loading="lazy" decoding="async" class="alignnone wp-image-238" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_15_Seite2.jpg" alt="RDLC5_15_Seite2" width="656" height="251" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_15_Seite2.jpg 828w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_15_Seite2-300x115.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_15_Seite2-768x294.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/RDLC5_15_Seite2-660x253.jpg 660w" sizes="auto, (max-width: 656px) 100vw, 656px" /> So nun hat man zwei verschieden große Köpfe auf Seite 1 und den folgenden Seiten. Hier findet ihr wie immer das Objekt: 160312_RobertsVKRechnung Falls Fragen bestehen, dann schreibt mir einfach einen Kommentar. The post RDLC für NAV Entwickler #5 – RDLC Belegdesign – Grundlagen & unterschiedliche Kopfgrößen first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
.NET – Modale Eingabeaufforderung – Ghostscript Komprimierung von PDF-Dateien
Hallo Leute, in einem meiner letzten Projekte habe ich mit dem NAS automatisiert Lieferscheine gedruckt. Diese werden im Stapel gedruckt und hatten riesige Größen von größer als 30 MB. Diese Lieferscheine sollten dann anschließend per Mail verschickt werden. Wie man sicherlich weiß, gibt es je nach Exchangeserver Limits, die ich mit diesen Dateianhängen überschritten hätte.… Weiterlesen » The post .NET – Modale Eingabeaufforderung – Ghostscript Komprimierung von PDF-Dateien first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Hallo Leute, in einem meiner letzten Projekte habe ich mit dem NAS automatisiert Lieferscheine gedruckt. Diese werden im Stapel gedruckt und hatten riesige Größen von größer als 30 MB. Diese Lieferscheine sollten dann anschließend per Mail verschickt werden. Wie man sicherlich weiß, gibt es je nach Exchangeserver Limits, die ich mit diesen Dateianhängen überschritten hätte. Ich möchte daher heute auf eine Möglichkeit eingehen, die wir seit der Einführung von .NET haben (seit NAV 2009). Wir können externe Programme beispielsweise per Eingabeaufforderung aufrufen und das System zwingen zu warten bis auch die externe Verarbeitung, aufgerufen durch die Eingabeaufforderung, fertig ist. Dies möchte ich heute etwas näher am Beispiel von Ghostscript und den dort integrierten Komprimierungsmöglichkeiten erläutern. Zu aller erst drucke ich dafür in einer NAV 2016 eine Auftragsbestätigung ohne Filtereingaben mit 30 Kopien und speichere diese als PDF. Das soll in diesem Fall mein Kundenbeispiel simulieren und eine große PDF erzeugen. In der „Debitoren & Verkauf Einrichtung“ habe ich die Logoposition auf rechts gesetzt, damit die Datei größer wird. <img loading="lazy" decoding="async" class="alignnone wp-image-195 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_1_Auftragsbestätigung.jpg" alt="NET_1_Auftragsbestätigung" width="467" height="534" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_1_Auftragsbestätigung.jpg 549w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_1_Auftragsbestätigung-262x300.jpg 262w" sizes="auto, (max-width: 467px) 100vw, 467px" /> Meine PDF hat jetzt eine Größe von 21,6 MB mit 1302 Seiten und wir sprechen von einem Standardbeleg. Das zeigt schon wohin die Reise gehen kann, wenn die PDF-Logik aus Dynamics NAV verwendet wird. <img loading="lazy" decoding="async" class="alignnone wp-image-196 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_2_PDFGröße.jpg" alt="NET_2_PDFGröße" width="331" height="452" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_2_PDFGröße.jpg 376w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_2_PDFGröße-220x300.jpg 220w" sizes="auto, (max-width: 331px) 100vw, 331px" /> Ich kann natürlich jetzt versuchen, das Druckbild oder die angedruckten Bilder zu verkleinern. Ich kann auch die Berichtseigenschaft bzw. Servertiereigenschaft: PDFFontEmbedding auf Yes setzen. Aber nehmen wir mal das Worst-Case Szenario an. Ich habe einen integrierten Barcode, belegabhängige Bilder und eine kundenindividuelle Schriftart in meinem Kundenbeleg. In diesem Fall kann ich meine Tricks nicht anwenden und muss also einen anderen Weg finden. In meinem Fall werde ich nun ein paar kleine Zeilen Code schreiben und das Ganze mit Ghostscript erheblich verkleinern ohne die Qualität groß zu verändern. Zu aller erst installiere ich dafür Ghostscript. Ich verwende die Version gs9.18 – 64 Bit, da ich dies auf der Service Tier (läuft auch mit 64 Bit) ausführen möchte. Nach der Intsallation steht mir hier Ghostscript zur Verfügung: <img loading="lazy" decoding="async" class="alignnone wp-image-199 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_3_GS_2.jpg" alt="NET_3_GS_2" width="695" height="333" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_3_GS_2.jpg 787w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_3_GS_2-300x144.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_3_GS_2-768x368.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_3_GS_2-660x316.jpg 660w" sizes="auto, (max-width: 695px) 100vw, 695px" /> Ich passe jetzt den Bericht 205 kurz an und setze die Kopienanzahl immer auf 30, damit ich mein Beispiel auch automatisiert nachstellen kann. Dafür füge ich eine neue Funktion ein, damit ich die Anzahl der Kopien von „Außen“ setzen kann. <img loading="lazy" decoding="async" class="alignnone wp-image-200 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_4_AB_NoOfCopies.jpg" alt="NET_4_AB_NoOfCopies" width="1022" height="592" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_4_AB_NoOfCopies.jpg 1234w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_4_AB_NoOfCopies-300x174.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_4_AB_NoOfCopies-768x445.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_4_AB_NoOfCopies-1024x593.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_4_AB_NoOfCopies-660x382.jpg 660w" sizes="auto, (max-width: 1022px) 100vw, 1022px" /> Nun erstelle ich eine neue Codeunit und erzeuge eine PDF über alle Aufträge im System mit jeweils 30 Kopien. <img loading="lazy" decoding="async" class="alignnone wp-image-201 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_5_AB_PDFErstellung.jpg" alt="NET_5_AB_PDFErstellung" width="708" height="397" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_5_AB_PDFErstellung.jpg 838w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_5_AB_PDFErstellung-300x168.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_5_AB_PDFErstellung-768x431.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_5_AB_PDFErstellung-660x370.jpg 660w" sizes="auto, (max-width: 708px) 100vw, 708px" /> Mit einem RUN auf die Codeunit erzeugt der Server die AB.PDF im Ordner C:\TEMP\ (Bei mir läuft Server und Client auf einer Maschine, daher berücksichtige ich kein 3-Tier File Management). <img loading="lazy" decoding="async" class="alignnone wp-image-202 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_6_AB_Datei.jpg" alt="NET_6_AB_Datei" width="669" height="264" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_6_AB_Datei.jpg 776w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_6_AB_Datei-300x118.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_6_AB_Datei-768x303.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_6_AB_Datei-660x260.jpg 660w" sizes="auto, (max-width: 669px) 100vw, 669px" /> Nun werde ich die PDF mit Ghostscript und der Eingabeaufforderung extrem verkleinern. Das Ganze berücksichtigt folgende Dinge: Diverse Parameter aus der Ghostscript Online Hilfe. CMD läuft im Hintergrund CMD läuft Modal CMD wartet bis Ghostscript fertig ist. Folgende Variablen benutze ich: Name DataType Subtype Length SystemDiagnosticsProcess DotNet System.Diagnostics.Process.’System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′ SystemDiagnosticsProcessStartInfo DotNet System.Diagnostics.ProcessStartInfo.’System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′ SystemDiagnosticsProcessWindowsStyle DotNet System.Diagnostics.ProcessWindowStyle.’System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′ CommandParameter Text <img loading="lazy" decoding="async" class="alignnone wp-image-203" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_7_GS_Komprimierung.jpg" alt="NET_7_GS_Komprimierung" width="1040" height="500" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_7_GS_Komprimierung.jpg 1668w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_7_GS_Komprimierung-300x144.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_7_GS_Komprimierung-768x369.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_7_GS_Komprimierung-1024x492.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_7_GS_Komprimierung-660x317.jpg 660w" sizes="auto, (max-width: 1040px) 100vw, 1040px" /> Den Wert „-dNumRenderingThreads=X“ sollte man so verändern, wie man es für richtig hält. Dieser gibt an, wie viele CPU-Kerne verwendet werden dürfen. Die Message zum Schluss gibt das System erst aus, wenn die Komprimierung abgeschlossen ist. Jetzt führen wir das Ganze aus und schauen uns das Ergebnis an: <img loading="lazy" decoding="async" class="alignnone wp-image-204" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_8_GS_KomprimierungErgebnis.jpg" alt="NET_8_GS_KomprimierungErgebnis" width="667" height="247" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_8_GS_KomprimierungErgebnis.jpg 764w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_8_GS_KomprimierungErgebnis-300x111.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/03/NET_8_GS_KomprimierungErgebnis-660x244.jpg 660w" sizes="auto, (max-width: 667px) 100vw, 667px" /> Wenn das mal nicht ein gutes Ergebnis ist? Dann weiß ich auch nicht mehr weiter! Der Vorgang läuft komplett modal und komprimiert mit einem Faktor von 10 zu 1 bzw. 9 zu 1. Bei Fragen schreibt mir einen Kommentar! Hier sind die beiden Objekte, falls ihr es selber ausprobieren wollt! 160305_PDF_Ghostscript_Komprimierung The post .NET – Modale Eingabeaufforderung – Ghostscript Komprimierung von PDF-Dateien first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
RDLC für NAV Entwickler #4 – Kopieren von Berichten / Layouts
Nachdem wir eine einfache Debitorenstatistik im RDL erstellt haben, möchte ich nun zeigen, warum der Aufbau des Dataset so wichtig war. Die Details hatte ich hier beschrieben: RDLC für NAV Entwickler #1 – Allgemeine Informationen & das Dataset Wer den Bericht nutzen möchte, bzw. das Kopieren selbstständig nachvollziehen möchte, der kann sich den Bericht am Ende des Beitrages RDLC für… Weiterlesen » The post RDLC für NAV Entwickler #4 – Kopieren von Berichten / Layouts first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Nachdem wir eine einfache Debitorenstatistik im RDL erstellt haben, möchte ich nun zeigen, warum der Aufbau des Dataset so wichtig war. Die Details hatte ich hier beschrieben: RDLC für NAV Entwickler #1 – Allgemeine Informationen & das Dataset Wer den Bericht nutzen möchte, bzw. das Kopieren selbstständig nachvollziehen möchte, der kann sich den Bericht am Ende des Beitrages RDLC für NAV Entwickler #3 – Grundlagen des Layouts – Teil 2 „Der Textkörper“ als FOB oder TXT herunterladen. Ich möchte nochmal kurz daran erinnern, wie unser Dataset aussieht: <img loading="lazy" decoding="async" class="alignnone wp-image-166 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL4_1_Dataset.jpg" alt="RDL4_1_Dataset" width="1031" height="563" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL4_1_Dataset.jpg 1170w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL4_1_Dataset-300x164.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL4_1_Dataset-768x419.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL4_1_Dataset-1024x559.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL4_1_Dataset-660x360.jpg 660w" sizes="auto, (max-width: 1031px) 100vw, 1031px" /> Wir haben das Dataset ohne das Fieldmenü aufgebaut. Wenn bei jedem Feld „Customer.“ davorstehen würde, dann wäre der Kopieraufwand viel größer. Man stelle sich das bei einer Verkaufsrechnung vor, die man zu einem Verkaufsgutschrift machen möchte! Des Weiteren habe ich im Namen auch keinen Verweis auf den Debitoren hinterlegt. Das stellt sicher, dass ich auch im Layout nicht verwirrt werde, wenn ich aus der Debitorenstatistik eine Kreditorenstatistik mache und im RDL Layout ständig No_Customer / Name_Customer etc. finde. Wenn ich nun aus diesem Bericht eine Kreditorenstatistik machen möchte, nehme ich folgende Schritte vor: Kopieren des Berichts auf eine neue Nummer Umbenennen des Berichts zu „Vendor Statistic“ Änderung der Caption des Berichts zu „Vendor Statistic“ / „Kreditorenstatistik“ Ändern des „Customer“ DataItem zu Vendor Ändern des „Cust. Ledger Entry“ DataItem zu „Vendor Ledger Entry“ Ändern des DataItemView und DataItemLink vom Dataitem „Vendor Ledger Entry“ (Customer No. zu Vendor No.) Ändern des Label „ReportName“ zu „Vendor Statistic“ / „Kreditorenstatistik“ Der Bericht sieht dann nicht viel anders aus, als unsere Kundenstatistik und wir haben sieben kleine Schritte gebraucht! <img loading="lazy" decoding="async" class="alignnone wp-image-167 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL4_2_Dataset.jpg" alt="RDL4_2_Dataset" width="634" height="476" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL4_2_Dataset.jpg 781w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL4_2_Dataset-300x225.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL4_2_Dataset-768x576.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL4_2_Dataset-660x495.jpg 660w" sizes="auto, (max-width: 634px) 100vw, 634px" /> Speichern des Berichts und wir können den Bericht ausführen. So sieht das Ergebnis aus: <img loading="lazy" decoding="async" class="alignnone wp-image-168 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL4_3_Vorschau.jpg" alt="RDL4_3_Vorschau" width="1149" height="826" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL4_3_Vorschau.jpg 1315w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL4_3_Vorschau-300x216.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL4_3_Vorschau-768x552.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL4_3_Vorschau-1024x736.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL4_3_Vorschau-660x474.jpg 660w" sizes="auto, (max-width: 1149px) 100vw, 1149px" /> Ich habe diese Technik bereits bei Rechnungen, Gutschriften, Angebot, Auftragsbestätigungen und Co angewandt und so erreicht man enorme Einsparungen bei der Entwicklungszeit der Berichte. Bei diesem Bericht habe ich also 5 Minuten gebraucht um eine Kreditorenstatistik aus einer Debitorenstatistik zu erstellen und die Belege sind absolut identisch formatiert. Man kann sich jetzt vorstellen, was das für Belege und Corporate Design bedeutet. Die Belege sind absolut gleich und man muss maximal die Unterscheide im Layout bearbeiten (falls beispielsweise andere Felder im Layout gedruckt werden sollen). Ich bin gespannt, ob Microsoft auf auch diesen Zug aufspringt, da dies doch echt eine Alternative zu Fremdtools ist, oder? Für alle die es nicht glauben, können hier die Kreditorenstatistik herunterladen: R50001_Kreditorenstatistik_160228 The post RDLC für NAV Entwickler #4 – Kopieren von Berichten / Layouts first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
RDLC für NAV Entwickler #3 – Grundlagen des Layouts – Teil 2 „Der Textkörper“
Als Folgethema zum RDLC für NAV Entwickler #2 – Grundlagen des Layouts – Teil 1 „Der Kopf“ gehe ich nun auf die letzten Details eines normalen Berichts ein! Hierbei gehe ich Schritt für Schritt darauf ein, wie man möglichst effizient eine neue Datentabelle (Tablix) im RDL integriert und mit Daten füllt. Zu aller erst füge ich im Textkörper per… Weiterlesen » The post RDLC für NAV Entwickler #3 – Grundlagen des Layouts – Teil 2 „Der Textkörper“ first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Als Folgethema zum RDLC für NAV Entwickler #2 – Grundlagen des Layouts – Teil 1 „Der Kopf“ gehe ich nun auf die letzten Details eines normalen Berichts ein! Hierbei gehe ich Schritt für Schritt darauf ein, wie man möglichst effizient eine neue Datentabelle (Tablix) im RDL integriert und mit Daten füllt. Zu aller erst füge ich im Textkörper per Rechtsklick eine neue Tabelle (Tablix) ein. <img loading="lazy" decoding="async" class="alignnone wp-image-145 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_1_neueTabelle.jpg" alt="RDL3_1_neueTabelle" width="768" height="391" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_1_neueTabelle.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_1_neueTabelle-300x153.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_1_neueTabelle-660x336.jpg 660w" sizes="auto, (max-width: 768px) 100vw, 768px" /> Dann nehme ich folgende Schritte vor: Löschen zweiter Spalten. Entfernung der Randeinstellung (Border) der Tabelle von BorderColor Lightgrey auf Black und BorderStyle von Solid auf None. Verändern des Paddings von 2pt;2pt;2pt;2pt auf 2pt;2pt;0pt;0pt & Zeilenhöhe von 0,6 cm auf 0,423 cm. Umstellung der Schriftart von Arial auf Segoe UI und die Schriftgröße auf 9pt. Anschließend wähle ich nur die Zelle aus, in der Kopfzeile steht und stelle folgende Einstellungen ein: FontWeight – Bold / Textallign: Bottom Hinzufügen des Datasets zur Tabelle über die Eigenschaften der Tabelle. Hier die Schritte visuell dargestellt: <img loading="lazy" decoding="async" class="alignnone wp-image-146 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_2_TabelleSpaltenlöschen.jpg" alt="RDL3_2_TabelleSpaltenlöschen" width="745" height="323" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_2_TabelleSpaltenlöschen.jpg 745w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_2_TabelleSpaltenlöschen-300x130.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_2_TabelleSpaltenlöschen-660x286.jpg 660w" sizes="auto, (max-width: 745px) 100vw, 745px" /> <img loading="lazy" decoding="async" class="alignnone wp-image-147" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_3_Tabelle_Borderentfernen.jpg" alt="RDL3_3_Tabelle_Borderentfernen" width="1061" height="414" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_3_Tabelle_Borderentfernen.jpg 1485w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_3_Tabelle_Borderentfernen-300x117.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_3_Tabelle_Borderentfernen-768x299.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_3_Tabelle_Borderentfernen-1024x399.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_3_Tabelle_Borderentfernen-660x257.jpg 660w" sizes="auto, (max-width: 1061px) 100vw, 1061px" /> <img loading="lazy" decoding="async" class="alignnone wp-image-148" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_4_Tabelle_Sonstiges.jpg" alt="RDL3_4_Tabelle_Sonstiges" width="1147" height="451" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_4_Tabelle_Sonstiges.jpg 1430w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_4_Tabelle_Sonstiges-300x118.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_4_Tabelle_Sonstiges-768x302.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_4_Tabelle_Sonstiges-1024x402.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_4_Tabelle_Sonstiges-660x259.jpg 660w" sizes="auto, (max-width: 1147px) 100vw, 1147px" /> <img loading="lazy" decoding="async" class="alignnone wp-image-149" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_5_2_Tabelle_Eigenschaft.jpg" alt="RDL3_5_2_Tabelle_Eigenschaft" width="1038" height="389" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_5_2_Tabelle_Eigenschaft.jpg 1334w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_5_2_Tabelle_Eigenschaft-300x112.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_5_2_Tabelle_Eigenschaft-768x288.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_5_2_Tabelle_Eigenschaft-1024x384.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_5_2_Tabelle_Eigenschaft-660x247.jpg 660w" sizes="auto, (max-width: 1038px) 100vw, 1038px" /> <img loading="lazy" decoding="async" class="alignnone wp-image-150" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_5_3_Tabelle_EigenschaftDatset.jpg" alt="RDL3_5_3_Tabelle_EigenschaftDatset" width="501" height="530" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_5_3_Tabelle_EigenschaftDatset.jpg 691w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_5_3_Tabelle_EigenschaftDatset-284x300.jpg 284w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_5_3_Tabelle_EigenschaftDatset-660x698.jpg 660w" sizes="auto, (max-width: 501px) 100vw, 501px" /> Somit ist meine Tabelle vorbereitet. Ich bereite meine Tabelle immer am Anfang vor. Es gibt nämlich Eigenschaften, die später ausgeblendet werden, wenn man alle Zellen markiert und dann noch eine Einstellung verändern möchte. Somit spare ich bereits von Anfang an Zeit und konzentriere mich auch die korrekten Formatierungen. Es ist natürlich jedem selbst überlassen, welche Eigenschaften man verwenden möchte, aber die oben genannten Einstellungen kommen den Classic Einstellungen sehr nahe. Die Schriftart Segoe UI wird ebenfalls vom Standard genutzt. Ich füge nun 6 weitere Spalten ein. Unsere Tabelle sollte jetzt so aussehen. <img loading="lazy" decoding="async" class="alignnone wp-image-151" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_5_Tabelle_7Spalten.jpg" alt="RDL3_5_Tabelle_7Spalten" width="630" height="297" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_5_Tabelle_7Spalten.jpg 764w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_5_Tabelle_7Spalten-300x141.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_5_Tabelle_7Spalten-660x311.jpg 660w" sizes="auto, (max-width: 630px) 100vw, 630px" /> Nun können wir uns um die zu druckenden Daten kümmern. Klickt man die Tabelle an, dann hat sieht man eine „Zeilengruppe“ Details. <img loading="lazy" decoding="async" class="alignnone wp-image-152" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_6_Tabelle_Details.jpg" alt="RDL3_6_Tabelle_Details" width="709" height="664" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_6_Tabelle_Details.jpg 874w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_6_Tabelle_Details-300x281.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_6_Tabelle_Details-768x719.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_6_Tabelle_Details-660x618.jpg 660w" sizes="auto, (max-width: 709px) 100vw, 709px" /> Diese besitzt aktuell die Standardeinstellung. Man kann sich Gruppen im RDL wie OnAfterGetRecords-Trigger vorstellen. Sie laufen nämlich immer über das DataSet. Gruppen sind also die Möglichkeit unsere Datenquelle auch auszugeben. Dabei sind zwei Elemente sind wichtig: Filter – Gruppen können gefiltert werden. Damit wird definiert, welcher Bereich des Datasets gedruckt wird. Ist kein Filter gesetzt, dann wird das komplette Dataset in der Gruppe durchlaufen. Gruppierungsfelder – Pro Gruppe können beliebig viele Felder definiert werden, nach denen das Dataset gruppiert wird. Gruppiere ich also nach der Debitorennr., dann wird innerhalb der Gruppe nur eine Zeile pro Kunde ausgegeben, auch wenn es darunter x-Posten gibt. Diese zwei Eigenschaften machen wir uns natürlich zu Nutze. Für unseren Bericht „Debitorenstatistik“ benötigen wir zwei Gruppen! Eine Gruppe für die Debitoren und eine ungefilterte Detailgruppe zur Ausgabe der Debitorenposten. Daher füge ich per Rechtsklick auf die Details, eine übergeordnete Gruppe ein. <img loading="lazy" decoding="async" class="alignnone wp-image-153" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_7_Tabelle_NeueGruppe.jpg" alt="RDL3_7_Tabelle_NeueGruppe" width="425" height="184" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_7_Tabelle_NeueGruppe.jpg 522w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_7_Tabelle_NeueGruppe-300x130.jpg 300w" sizes="auto, (max-width: 425px) 100vw, 425px" /> Die neue Spalte am links, lösche ich gleich wieder, da ich diese Spalte nicht brauche. <img loading="lazy" decoding="async" class="alignnone wp-image-154" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_8_Tabelle_NeueGruppe2.jpg" alt="RDL3_8_Tabelle_NeueGruppe2" width="628" height="561" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_8_Tabelle_NeueGruppe2.jpg 731w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_8_Tabelle_NeueGruppe2-300x268.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_8_Tabelle_NeueGruppe2-660x590.jpg 660w" sizes="auto, (max-width: 628px) 100vw, 628px" /> Damit haben wir nun die Grundlage für unsere Datentabelle. Ich befülle die Tabelle nun mit Daten. Wie man die Felder anordnet oder wie man diese formiert möchte ich jedem selbst überlassen. <img loading="lazy" decoding="async" class="alignnone wp-image-155" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_9_Tabelle_Feldereingefügt.jpg" alt="RDL3_9_Tabelle_Feldereingefügt" width="889" height="598" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_9_Tabelle_Feldereingefügt.jpg 1261w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_9_Tabelle_Feldereingefügt-300x202.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_9_Tabelle_Feldereingefügt-768x516.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_9_Tabelle_Feldereingefügt-1024x689.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_9_Tabelle_Feldereingefügt-660x444.jpg 660w" sizes="auto, (max-width: 889px) 100vw, 889px" /> Wichtig ist nun, dass wir die Kopfzeile auf jeder Seite wiederholen und die Kundendaten wiederholen, wenn es einen Seitenumbruch gibt. Dafür muss der „Erweiterter Modus“ aktiviert werden. <img loading="lazy" decoding="async" class="alignnone wp-image-156" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_10_Tabelle_ErweiterterModus.jpg" alt="RDL3_10_Tabelle_ErweiterterModus" width="896" height="139" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_10_Tabelle_ErweiterterModus.jpg 1076w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_10_Tabelle_ErweiterterModus-300x47.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_10_Tabelle_ErweiterterModus-768x119.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_10_Tabelle_ErweiterterModus-1024x159.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_10_Tabelle_ErweiterterModus-660x102.jpg 660w" sizes="auto, (max-width: 896px) 100vw, 896px" /> Anschließend sehen wie auch die „statischen“ Zeilen in den Zeilengruppen. Damit der Kopf wiederholt wird und die Kundendaten wiederholt werden, muss die erste statische Zeile und die Kundenzeile mit den folgenden Eigenschaften ausgestattet werden. <img loading="lazy" decoding="async" class="alignnone wp-image-157" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_11_Tabelle_TransHeader.jpg" alt="RDL3_11_Tabelle_TransHeader" width="1091" height="409" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_11_Tabelle_TransHeader.jpg 1461w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_11_Tabelle_TransHeader-300x113.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_11_Tabelle_TransHeader-768x288.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_11_Tabelle_TransHeader-1024x384.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_11_Tabelle_TransHeader-660x248.jpg 660w" sizes="auto, (max-width: 1091px) 100vw, 1091px" /> Die Eigenschaft „HideIfNoRows“ blendet die Überschrift aus, wenn sich keine Datensätze im Filter befinden. Das halte ich in diesem Fall für nicht notwendig, sollte aber berücksichtigt werden, da Tabellen in Berichten nicht gedruckt werden, aber trotzdem Platz reservieren. Ich speichere das Layout und kann den Bericht nun ausführen. Dabei kann es je nach Datenbasis die unterschiedlichsten kleinen Probleme geben. Beispielsweise, dass Kunden gedruckt werden, die gar keine Posten haben, die Abstände sind zu knapp oder die Formatierungen gefallen einem nicht. Ist man mit allem fertig, dann sollte die Tabelle genau links oben im Textkörper positioniert werden. Ebenfalls sollte es keinen leeren Bereich im Bericht geben. Das würde nämlich nur dazu führen, dass Platz reserviert wird und das kann beispielsweise zu nicht gewollten Seitenumbrüchen führen. Mein Bericht sieht im Ergebnis so aus: <img loading="lazy" decoding="async" class="alignnone wp-image-158" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_12_Debitorenstatistik.jpg" alt="RDL3_12_Debitorenstatistik" width="685" height="510" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_12_Debitorenstatistik.jpg 830w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_12_Debitorenstatistik-300x223.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_12_Debitorenstatistik-768x572.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL3_12_Debitorenstatistik-660x491.jpg 660w" sizes="auto, (max-width: 685px) 100vw, 685px" /> Zum Prüfen oder einfach zum Schauen gibt es hier den Bericht als fob und txt: R50000_Debitorenstatistik_160227 The post RDLC für NAV Entwickler #3 – Grundlagen des Layouts – Teil 2 „Der Textkörper“ first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
RDLC für NAV Entwickler #2 – Grundlagen des Layouts – Teil 1 „Der Kopf“
Als Folgethema zum RDLC für NAV Entwickler #1 – Allgemeine Informationen & das Dataset möchte ich nun auf die Grundlagen des Layouts eingehen. Dabei werden wir die Grundlagen von RDL-Berichten erörtern, welche Programme wir nutzen können und wie wir den Kopf unseres Beleges erstellen können. Zu aller erst sollten wir uns damit beschäftigen, welche Programme wir für… Weiterlesen » The post RDLC für NAV Entwickler #2 – Grundlagen des Layouts – Teil 1 „Der Kopf“ first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Als Folgethema zum RDLC für NAV Entwickler #1 – Allgemeine Informationen & das Dataset möchte ich nun auf die Grundlagen des Layouts eingehen. Dabei werden wir die Grundlagen von RDL-Berichten erörtern, welche Programme wir nutzen können und wie wir den Kopf unseres Beleges erstellen können. Zu aller erst sollten wir uns damit beschäftigen, welche Programme wir für die einzelnen Dynamics NAV Versionen benötigen. Dabei gibt es in der Regel zwei Möglichkeiten: Report Builder Visual Studio Für eine gute Übersicht und Installationsanleitungen kann man den folgenden Beitrag im MSDynamics.de lesen: Link (Ein Dank an Natalie für die gute Zusammenstellung). Dazu ergänzend kann man für Dynamics NAV 2016 folgendes sagen: Auch dort funktioniert Visual Studio 2013 Community Edition, Visual Studio 2013 Professional oder der integrierte Report Builder. Ab Dynamics NAV 2016 CU1 (cumulative update 1) wird auch Visual Studio 2015 unterstützt. Vergleicht man den Report Builder und Visual Studio, dann sollten folgende Fakten berücksichtigt werden: Der Report Builder ist gegenüber Visual Studio stark eingeschränkt. Die wichtigsten Defizite sind meiner Meinung nach: Der Report Builder besitzt keine Dokumentgliederung. Dadurch ist es schier unmöglich in verschachtelten Berichten die Übersicht zu behalten. Sie zeigt an, wie die einzelnen Elemente verknüpft sind. Das ist wichtig, da es so etwas wie „Sections“ nicht mehr gibt. Es gibt aber vergleichbare Elemente, wie Gruppen und Rechtecke bei denen wie die Sichtbarkeit steuern können. In diesem Fall benötigen wir eine exakte Übersicht, welches Element zu welchem übergeordneten Element gehört. <img loading="lazy" decoding="async" class="alignnone wp-image-102" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/VisualStudio_Dokumentgliederung_Aufruf.jpg" alt="VisualStudio_Dokumentgliederung_Aufruf" width="619" height="609" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/VisualStudio_Dokumentgliederung_Aufruf.jpg 857w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/VisualStudio_Dokumentgliederung_Aufruf-300x295.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/VisualStudio_Dokumentgliederung_Aufruf-768x755.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/VisualStudio_Dokumentgliederung_Aufruf-660x649.jpg 660w" sizes="auto, (max-width: 619px) 100vw, 619px" /> <img loading="lazy" decoding="async" class="alignnone wp-image-100" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/VisualStudio_Dokumentgliederung.jpg" alt="VisualStudio_Dokumentgliederung" width="307" height="443" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/VisualStudio_Dokumentgliederung.jpg 420w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/VisualStudio_Dokumentgliederung-208x300.jpg 208w" sizes="auto, (max-width: 307px) 100vw, 307px" /> Der Report Builder besitzt keine vernünftigen Möglichkeiten um die Ausrichtung der Elemente zuzuordnen: <img loading="lazy" decoding="async" class="alignnone wp-image-105" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/VisualStudio_Ausrichtungf.jpg" alt="VisualStudio_Ausrichtungf" width="701" height="547" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/VisualStudio_Ausrichtungf.jpg 913w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/VisualStudio_Ausrichtungf-300x234.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/VisualStudio_Ausrichtungf-768x599.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/VisualStudio_Ausrichtungf-660x515.jpg 660w" sizes="auto, (max-width: 701px) 100vw, 701px" /> Der Report Builder besitzt keine Möglichkeit auf den benutzerdefinierten Code des Berichts zuzugreifen: <img loading="lazy" decoding="async" class="alignnone wp-image-106 " src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/VisualStudio_Berichtseigenschaften.jpg" alt="VisualStudio_Berichtseigenschaften" width="621" height="132" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/VisualStudio_Berichtseigenschaften.jpg 706w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/VisualStudio_Berichtseigenschaften-300x64.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/VisualStudio_Berichtseigenschaften-660x140.jpg 660w" sizes="auto, (max-width: 621px) 100vw, 621px" /> <img loading="lazy" decoding="async" class="alignnone wp-image-107" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/VisualStudio_Berichtseigenschaften_Code.jpg" alt="VisualStudio_Berichtseigenschaften_Code" width="598" height="437" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/VisualStudio_Berichtseigenschaften_Code.jpg 765w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/VisualStudio_Berichtseigenschaften_Code-300x219.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/VisualStudio_Berichtseigenschaften_Code-660x482.jpg 660w" sizes="auto, (max-width: 598px) 100vw, 598px" /> Es gibt noch mehr Restriktionen, allerdings sind diese drei Restriktionen für mich die Wesentlichsten. Meiner Erfahrung nach eignet sich der Report Builder ausschließlich für Formatierungen oder kleinen Änderungen am Layout. Der Aufbau eines komplexen RDL-Berichtes sollte nicht mit dem Report Builder durchgeführt werden. Die Erstellung einer kleinen Auswertung ist aber dennoch mit dem Report Builder möglich! Ob sich Visual Studio oder der Report Builder startet, können wir direkt in den Optionen des Dynamics NAV Entwicklungsclient festlegen. Je nach dem, wie wir die Option festlegen steuert NAV, welches Programm beim Aufruf des Layouts geöffnet wird. <img loading="lazy" decoding="async" class="alignnone wp-image-99" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/DynamicsNAV_Entwicklung_ReportBuilderEinstellung.jpg" alt="DynamicsNAV_Entwicklung_ReportBuilderEinstellung" width="879" height="489" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DynamicsNAV_Entwicklung_ReportBuilderEinstellung.jpg 1073w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DynamicsNAV_Entwicklung_ReportBuilderEinstellung-300x167.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DynamicsNAV_Entwicklung_ReportBuilderEinstellung-768x427.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DynamicsNAV_Entwicklung_ReportBuilderEinstellung-1024x570.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DynamicsNAV_Entwicklung_ReportBuilderEinstellung-660x367.jpg 660w" sizes="auto, (max-width: 879px) 100vw, 879px" /> Wir setzen uns heute mit Visual Studio 2015 auseinander und wie wir das Layout unserer Debitorenstatistik erstellen können. Nach dem wir das Layout geöffnet haben, sollten wir zu aller erst die Berichtseigenschaften öffnen: <img loading="lazy" decoding="async" class="alignnone wp-image-112" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Berichtseigenschaften_Standard-e1456062054155.jpg" alt="RDL_Berichtseigenschaften_Standard" width="674" height="494" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Berichtseigenschaften_Standard-e1456062054155.jpg 765w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Berichtseigenschaften_Standard-e1456062054155-300x220.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Berichtseigenschaften_Standard-e1456062054155-660x484.jpg 660w" sizes="auto, (max-width: 674px) 100vw, 674px" /> Wie wir sehen, sind die Standardeigenschaften „Seiteneinheiten“ auf „Zoll“ und Papierformat auf „Letter“ eingestellt. Des Weiteren sind in einem neuen Bericht keine Ränder voreingestellt. Es gibt zwar auch die Möglichkeit, eine Vorlage zu laden, wenn ein neuer Bericht erstellt wird, aber darauf gehen wir heute nicht ein. Ich kann nur dazu raten, dass die Einheit auf jeden Fall auf Zentimeter umgestellt wird. Wir können uns alle daran erinnern, dass in Classic Berichten, die Eigenschaften der Größe oder Positionierung einer Textbox in Millimeter angegeben wurden. Würde man nun die Einheit nicht ändern, dann werden alle eingefügten Elemente mit Zoll-Eigenschaften eingefügt. Ändert man die Seiteneinheit, dann werden neu eingefügte Elemente mit Zentimeter eingefügt und es ist wesentlich leichter diese entsprechend eines alten Classic-Berichtes zu übernehmen oder zu vergleichen. Ebenfalls ist die Höhe einer Textbox im Classic Client 423 mm. Im RDL kann ich dann also die Höhe von 4,23 cm hinterlegen. Es ist also sehr hilfreich, wenn diese Eigenschaft von Anfang an geändert wird. Sind bereits Elemente im Bericht enthalten und man ändert die Einstellung, dann gilt diese Änderung nur für neue Elemente. Des Weiteren können wir hier die Ausrichtung „Hochformat“ / „Querformat“ angeben! Zusätzlich kann man auch das Papierformat angeben. Hierbei ist folgendes zu berücksichtigen. Im Gegensatz zum Classic Client kann ich hier jede Einstellung vornehmen, die ich benötige. Auch Einstellungen eines Nadeldruckers, trage ich her bei Breite und Höhe manuell ein! Bei der Übertragung des Berichts an den Drucker wird das bestmögliche Seitenlayout gefunden und verwendet. Wichtig ist dabei aber auch, dass die Druckerauswahl bei nicht standardisierten Papierformaten korrekt gepflegt ist. Zu guter letzt können wir unsere Seitenränder einstellen. Im Falle meiner Debitorenstatistik sehen die Eigenschaften dann so aus: <img loading="lazy" decoding="async" class="alignnone wp-image-113" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Berichtseigenschaften_Geändert.jpg" alt="RDL_Berichtseigenschaften_Geändert" width="675" height="493" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Berichtseigenschaften_Geändert.jpg 765w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Berichtseigenschaften_Geändert-300x219.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Berichtseigenschaften_Geändert-660x482.jpg 660w" sizes="auto, (max-width: 675px) 100vw, 675px" /> Erst jetzt beginne ich mit dem Hinzufügen von Elementen in meinen Bericht. Standardmäßig starten wir mit einem leeren Textkörper. <img loading="lazy" decoding="async" class="alignnone wp-image-114" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Textkörper.jpg" alt="RDL_Layout_Textkörper" width="924" height="300" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Textkörper.jpg 1069w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Textkörper-300x97.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Textkörper-768x249.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Textkörper-1024x332.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Textkörper-660x214.jpg 660w" sizes="auto, (max-width: 924px) 100vw, 924px" /> Mit einem simplen Rechtsklick in den Textkörper kann ich dann eine Kopf- oder Fußzeile hinzufügen: .<img loading="lazy" decoding="async" class="alignnone wp-image-115" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Kopf_Fußzeile_Einfügen.jpg" alt="RDL_Layout_Kopf_Fußzeile_Einfügen" width="511" height="386" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Kopf_Fußzeile_Einfügen.jpg 658w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Kopf_Fußzeile_Einfügen-300x227.jpg 300w" sizes="auto, (max-width: 511px) 100vw, 511px" /> In unserem Fall erstelle ich nun eine Kopfzeile. Man beachte dabei, dass der Platz, den die Kopfzeile verbraucht auf jeder Seite reserviert wird, egal welche Sichtbarkeiten ich nachher im Layout hinterlege. Das Gleiche gilt ebenfalls für die Fußzeile. Das ist eine der primären Restriktionen von RDL Berichten. Wie man das zum Teil austricksen kann, darauf werde ich zu einem späteren Zeitpunkt eingehen! <img loading="lazy" decoding="async" class="alignnone wp-image-116" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Kopfzeile.jpg" alt="RDL_Layout_Kopfzeile" width="957" height="326" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Kopfzeile.jpg 1045w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Kopfzeile-300x102.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Kopfzeile-768x262.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Kopfzeile-1024x349.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Kopfzeile-660x225.jpg 660w" sizes="auto, (max-width: 957px) 100vw, 957px" /> Um nun eine Debitorenstatistik zu erstellen, benötigen wir zwei Elemente: Kopfzeile mit entsprechenden Informationen Tabelle mit Debitoreninformationen (im folgenden Beitrag) Kopfzeile: Hier führe ich folgende Schritte durch: Einfügen eines Rechtecks im Kopf, Umbenennung des Rechtecks zu „Header“ und Veränderung der Breite zu 19 cm (21 cm – 1 cm linker Rand – 1 cm rechter Rand). Einfügen einer Textbox in das Rechteck „Header“ (Rechtsklick in das Rechteck) und die Veränderung der Einstellungen der Textbox: Size – Heigth: 0,6 cm zu 0,423 cm Padding: von 2pt;2pt;2pt;2pt zu 2pt;2pt;0pt;0pt Font: von Arial zu Segoe UI Fontsize: von 1opt zu 9pt Kopieren der Textbox im Kopf sieben mal Mit diesen Schritten habe ich 7 Textboxen mit einem einheitlichen Layout und kann das Design gestalten. Ich achte beim Kopieren auch darauf, dass die Elemente in der gleichen Reihenfolge angeordnet sind, in denen ich die Textboxen eingefügt habe. Danach ordne ich die fünf Textboxen an (vier linkbündig und drei Textboxen rechtsbündig). Dabei verzichte bei der Ausrichtung so weit es geht auf die Maus. Entweder richte ich Elemente mit den Pfeiltasten aus oder ich markiere zwei oder mehrere Elemente und verwende die oben gezeigten Ausrichtungsfunktionen von Visual Studio. Damit sollte man ein wenig herum spielen. Das Layout sieht jetzt so aus: <img loading="lazy" decoding="async" class="alignnone wp-image-122" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Kopfzeile_mit_Elementen3.jpg" alt="RDL_Layout_Kopfzeile_mit_Elementen3" width="1011" height="297" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Kopfzeile_mit_Elementen3.jpg 1178w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Kopfzeile_mit_Elementen3-300x88.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Kopfzeile_mit_Elementen3-768x226.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Kopfzeile_mit_Elementen3-1024x301.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Kopfzeile_mit_Elementen3-660x194.jpg 660w" sizes="auto, (max-width: 1011px) 100vw, 1011px" /> Folgende Inhalte möchte ich einfügen: Textbox1: ReportName Textbox2: Mandantename Textbox3: Ausführungsdatum + Zeit Textbox4: Seitencaption + Seitennummer + Gesamtseitenanzahl Textbox5: Ausführender Benutzer Textbox6: Eingebebener Filter auf dem DataItem Customer Textbox7: Eingebebener Filter auf dem DataItem „Customer Ledger Entry“ Wer aufgepasst hat, der stellt fest, dass wir den Mandantenname. sowie die Filterungen noch nicht im Dataset aufgenommen werden. Des Weiteren fehlt uns noch das Label PageNoCaption. Die restlichen Informationen haben wir im RDL zur Verfügung. Ich erweitere also das Dataset wie folgt: <img loading="lazy" decoding="async" class="alignnone wp-image-124" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/Dataset_Update.jpg" alt="Dataset_Update" width="819" height="446" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Dataset_Update.jpg 1171w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Dataset_Update-300x163.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Dataset_Update-768x418.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Dataset_Update-1024x558.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Dataset_Update-660x360.jpg 660w" sizes="auto, (max-width: 819px) 100vw, 819px" /> Wichtig ist dabei, dass man das Layout neu öffnen müssen, damit die Felder auch in Visual Studio zur Verfügung stehen. Nun hinterlege ich wie oben beschrieben den Ausdruck der Textboxen un benenne die Textboxen gemäß des Ausdrucks um: Textbox1 zu „ReportName“ – Ausdruck: =Parameters!ReportName.Value / Fontweigth: Bold Textbox2 zu „CompanyName“ – Ausdruck: =First(Fields!CompanyName.Value, „DataSet_Result“) Textbox3 zu „ExecutionTime“ – Ausdruck: =Globals!ExecutionTime / Format: dd.MM.yyyy HH:mm Textbox4 zu „PageNo“ – Ausdruck: =Parameters!PageNoCaption.Value & “ “ & Globals!PageNumber & “ / “ & Globals!TotalPages Textbox5 zu „UserID“ – Ausdruck: =User!UserID Textbox6 zu „GetFilters“ – Ausdruck: =First(Fields!GetFilters.Value, „DataSet_Result“) Textbox7 zu „GetFilters_Entry“ – Ausdruck: =First(Fields!GetFilters_Entry.Value, „DataSet_Result“) Das Ergebnis sieht dann so aus: <img loading="lazy" decoding="async" class="alignnone wp-image-129" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Kopfzeile_mit_Asudrücken2.jpg" alt="RDL_Layout_Kopfzeile_mit_Asudrücken2" width="949" height="278" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Kopfzeile_mit_Asudrücken2.jpg 1188w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Kopfzeile_mit_Asudrücken2-300x88.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Kopfzeile_mit_Asudrücken2-768x225.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Kopfzeile_mit_Asudrücken2-1024x300.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_Layout_Kopfzeile_mit_Asudrücken2-660x193.jpg 660w" sizes="auto, (max-width: 949px) 100vw, 949px" /> Ich kann also sofort über die Dokumentgliederung das entsprechende Element auswählen und bearbeiten. Wenn wir später mit Verschachtelungen arbeiten und wir unterschiedliche Köpfe auf der ersten Seite oder der folgenden Seiten haben, dann werden wir erkennen, warum es Sinn macht, am Anfang etwas mehr Zeit in die Gestaltung unseres Berichtes zu investieren. Dann speichern wir das RDL Layout und klicken in die DataItem Struktur. Dabei kommt folgende Meldung: <img loading="lazy" decoding="async" class="alignnone wp-image-127" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_UpdateRDLC.jpg" alt="RDL_UpdateRDLC" width="384" height="168" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_UpdateRDLC.jpg 490w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_UpdateRDLC-300x131.jpg 300w" sizes="auto, (max-width: 384px) 100vw, 384px" /> Diese bestätigen wir mit Ja! Dadurch wir das Layout im Entwicklungsclient gespeichert. Des Weiteren stelle ich in den Berichtseigenschaften des Entwicklungsclients den „PreViewMode“ auf PrintLayout um. Welche Vor- und Nachteile die beiden Einstellungen (Normal, PrintLayout) haben, werde ich später erläutern. Ich verwende hier das PrintLayout, da ich den Bericht so sehen möchte, wie er später ausgedruckt vorliegt. <img loading="lazy" decoding="async" class="alignnone wp-image-130" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_PreViewMode.jpg" alt="RDL_PreViewMode" width="291" height="400" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_PreViewMode.jpg 336w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/RDL_PreViewMode-218x300.jpg 218w" sizes="auto, (max-width: 291px) 100vw, 291px" /> Die Vorschau sieht dann so aus: <img loading="lazy" decoding="async" class="alignnone wp-image-131" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/Debitorenstatistik_Vorschau2.jpg" alt="Debitorenstatistik_Vorschau2" width="725" height="436" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Debitorenstatistik_Vorschau2.jpg 974w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Debitorenstatistik_Vorschau2-300x180.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Debitorenstatistik_Vorschau2-768x462.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Debitorenstatistik_Vorschau2-660x397.jpg 660w" sizes="auto, (max-width: 725px) 100vw, 725px" /> Damit haben wir den Grundstein unseres Berichtes, den Kopf erstellt und eine Menge über die Grundlagen in Visual Studio gelernt. In folgenden Beitrag werde ich „Best Practice Methoden“ für die Datentabelle geben. Für Fragen oder Anregungen schreibt mir einen Kommentar. The post RDLC für NAV Entwickler #2 – Grundlagen des Layouts – Teil 1 „Der Kopf“ first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Interaktive Sortierung in Pages mit AutoSplitKey Eigenschaft
Wie bereits bekannt, kann mit Dynamics NAV 2013 mit einem einfachen Klick auf die Überschrift die Maske umsortiert werden. Dieses Feature war ein Meilenstein, da der Schlüssel nicht an der Tabelle existieren musste. NAV kann also ab der Version 2013 die Sortierung direkt in der Ansicht ändern. Dieses Feature steht uns in fast allen Pages als Standard… Weiterlesen » The post Interaktive Sortierung in Pages mit AutoSplitKey Eigenschaft first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Wie bereits bekannt, kann mit Dynamics NAV 2013 mit einem einfachen Klick auf die Überschrift die Maske umsortiert werden. Dieses Feature war ein Meilenstein, da der Schlüssel nicht an der Tabelle existieren musste. NAV kann also ab der Version 2013 die Sortierung direkt in der Ansicht ändern. Dieses Feature steht uns in fast allen Pages als Standard zur Verfügung. Es gibt nun aber Pages in denen ich das persönlich doch gerne abschalten möchte. Darunter fallen alle Pages mit aktivierter AutoSplitKey Eigenschaft. Das liegt nämlich daran, dass ich beim Einfügen von neuen Zeilen ein Problem bekomme, wenn die Maske nicht nach dem Feld „Zeilennr.“ sortiert ist. Man kennt das Phänomen aus beispielsweise aus dem Verkaufsauftrag. Normalerweise ist die Maske nach „Zeilennr.“ sortiert: <img loading="lazy" decoding="async" class="alignnone wp-image-80" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/Verkaufsauftrag_Sortierung_Zeilennr..jpg" alt="Verkaufsauftrag_Sortierung_Zeilennr." width="1065" height="399" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Verkaufsauftrag_Sortierung_Zeilennr..jpg 1239w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Verkaufsauftrag_Sortierung_Zeilennr.-300x112.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Verkaufsauftrag_Sortierung_Zeilennr.-768x288.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Verkaufsauftrag_Sortierung_Zeilennr.-1024x383.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Verkaufsauftrag_Sortierung_Zeilennr.-660x247.jpg 660w" sizes="auto, (max-width: 1065px) 100vw, 1065px" /> Zum besseren Darstellung habe die Zeilennr. als erstes Feld eingeblendet! Sortiere ich nun nach Beschreibung. dann sieht die Maske so aus:<img loading="lazy" decoding="async" class="alignnone wp-image-81" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/Verkaufsauftrag_Sortierung_Beschreibung..jpg" alt="Verkaufsauftrag_Sortierung_Beschreibung." width="1071" height="398" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Verkaufsauftrag_Sortierung_Beschreibung..jpg 1236w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Verkaufsauftrag_Sortierung_Beschreibung.-300x111.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Verkaufsauftrag_Sortierung_Beschreibung.-768x285.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Verkaufsauftrag_Sortierung_Beschreibung.-1024x380.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Verkaufsauftrag_Sortierung_Beschreibung.-660x245.jpg 660w" sizes="auto, (max-width: 1071px) 100vw, 1071px" /> Nun fällt schon auf, dass die erste Zeile die Zeilennr. „40000“ und die zweite Zeile die Zeilennr. „20000“ aufweist. In diesem Fall wird der AutoSplitKey schief gehen, wenn ich zwischen der ersten und der zweiten Zeile einen neuen Datensatz einfügen möchte. <img loading="lazy" decoding="async" class="alignnone wp-image-82 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/Verkaufsauftrag_Sortierung_Fehler.jpg" alt="Verkaufsauftrag_Sortierung_Fehler" width="303" height="135" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Verkaufsauftrag_Sortierung_Fehler.jpg 303w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Verkaufsauftrag_Sortierung_Fehler-300x134.jpg 300w" sizes="auto, (max-width: 303px) 100vw, 303px" /> Das kann nun in jeder Erfassungsmaske passieren. Das Problem ist nun folgendes: Normalerweise wird die Zeilennr. nicht als Feld angezeigt. In der Regel ist das Feld auch vollkommen uninteressant für den Endanwender. Es gibt nun zwei Möglichkeiten: Maske neu öffnen (stellt die Standardsortierung wieder her) Anpassungen deaktivieren am Profil: Der NAV Standard gibt mir die Möglichkeit, dass ich am Profil einen Haken setzen kann, dass persönliche Anpassungen des Benutzers verhindert werden. Das finde ich persönlich nicht ausreichend, weil ich möchte, dass jeder Benutzer seine Spalten, Felder oder Aktionen so anordnet, wie es die Person für richtig hält. Ich möchte eigentlich nur den Fehler mit dem AutoSplitKey verhindern. Dafür gibt es einen einfachen Trick. In Masken mit Einrückung steht das Feature nämlich nicht zur Verfügung. Ich muss also nur eine Einrückung simulieren um die Sortierung abzuschalten, aber alle anderen Möglichkeiten zu erhalten. Dafür hinterlege ich in der Subpage auf der RepeaterGroup die Eigenschaft „IndentationColumnName“. Dabei kann ein beliebiger Wert eingetragen werden (beispielsweise „1“): <img loading="lazy" decoding="async" class="alignnone wp-image-83" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/Verkaufsauftrag_Einrückung.jpg" alt="Verkaufsauftrag_Einrückung" width="1058" height="396" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Verkaufsauftrag_Einrückung.jpg 1224w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Verkaufsauftrag_Einrückung-300x112.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Verkaufsauftrag_Einrückung-768x287.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Verkaufsauftrag_Einrückung-1024x383.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/Verkaufsauftrag_Einrückung-660x247.jpg 660w" sizes="auto, (max-width: 1058px) 100vw, 1058px" /> Nach dem Speichern des Objekts ist die Sortierung nur für diese Page deaktiviert. Alle anderen Features, wie Spalten auswählen, Fixierung oder die Schnelleingabe kann der Anwender selbst steuern. Die Maske hat trotzdem keine Einrückung, verhält sich aber wie die Sachkontenübersicht. Dort kann ich auch nicht umsortieren, da die Maske eine Einrückung berücksichtigt. Es ist sicherlich nicht die schönste Variante, aber es ist eine Möglichkeit, dieses Problem zu lösen. Probiert es einfach mal aus! The post Interaktive Sortierung in Pages mit AutoSplitKey Eigenschaft first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
RDLC für NAV Entwickler #1 – Allgemeine Informationen & das Dataset
Es gibt immer wieder die gleiche Schwierigkeit im NAV-Projektgeschäft. Ob in einer Neueinführung oder in einem Update, die Thematik Berichte bleibt nicht aus. Dabei gibt es natürlich mehrere Möglichkeiten. Von Konvertierungstools (Classic zu RDLC) über eigenen Berichtsarten, die eine eigene Renderlogik und einen eigenen Designer haben, zu klassischen RDLC Berichten gibt es aktuell alles auf dem Markt.… Weiterlesen » The post RDLC für NAV Entwickler #1 – Allgemeine Informationen & das Dataset first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Es gibt immer wieder die gleiche Schwierigkeit im NAV-Projektgeschäft. Ob in einer Neueinführung oder in einem Update, die Thematik Berichte bleibt nicht aus. Dabei gibt es natürlich mehrere Möglichkeiten. Von Konvertierungstools (Classic zu RDLC) über eigenen Berichtsarten, die eine eigene Renderlogik und einen eigenen Designer haben, zu klassischen RDLC Berichten gibt es aktuell alles auf dem Markt. Wenn man danach sucht wird man auch fündig! Aber was ist nun der beste Weg um das Problem zu lösen? Diese Frage muss jeder für sich beantworten. Ich denke alles hat Vor- und Nachteile. Als Vertreter von RDLC Berichten habe ich auch meine Erfahrungen gemacht. Ebenfalls habe ich mich mit den diversen Tools beschäftigt, aber kam nicht um folgende Argumente herum: Einsetzen der Technologie von Microsoft: Ok, es ist ja nicht so, dass Microsoft in NAV 2017 die Berichtslogik komplett über den Haufen wirft und etwas komplett Neues integriert, aber ich halte es für besser, nur von Microsoft abhängig zu sein. Tools, die den Bericht technisch außerhalb von NAV aufbauen und ebenfalls designen, müssen schließlich auch gewartet werden. RDLC ist gar nicht so furchtbar schlecht, wie viele behaupten. Klar, es ist nicht die perfekte Technologie für NAV Berichte, aber es ist auch nicht die Schlechteste. Trotz des doch nicht so leichten Einstiegs in das Thema RDLC bin ich schnell daran gewachsen. Vieles lässt sich in RDLC lösen und Probleme wird es vermutlich mit jeder Technologie geben, ob nun mit RDLC oder ohne. Dem Gegenüber steht: Schnell und einfach Berichte designen Wer Classic Berichte kann, kann es auch mit unserem Tool oder einfacher Einstieg in das Tool Mehr Möglichkeiten als im RDLC … Wie gesagt, das sollte jeder für sich entscheiden, ich halte mich dort an RDLC. Wenn ich einen normalen Arbeitstag betrachte, dann werde ich bestimmt 1x pro Tag zum Thema RDLC befragt. Gefühlt ist hier die Unsicherheit noch groß. Daher möchte ich die Serie RDLC für NAV Entwickler starten, da es gar nicht so schwierig ist, den Einstieg in das Thema zu lernen und ein paar Kernthemen davon zu erläutern. In meinem ersten Blogeintrag möchte ich mich daher auf das Dataset beziehen und dazu meine Erfahrungen teilen. Was ist also das Dataset? Im Vergleich zu Classic Berichten, definiere ich die Felder selbst, die ich innerhalb meines Berichtes nutzen möchte. Im Classic standen mir durch die integrierte Lösung, des Section-Designers, auch der Zugriff auf alle meine Felder und Variablen zur Verfügung. Im RDLC müssen wir jedes Feld oder jede Variable explizit angeben, sodass diese im Design an Visual Studio oder an den Report Builder übergeben werden. Nehmen wir mal an, wir bauen uns eine Debitorenstatistik, die zu jedem Kunden alle Debitorenposten ausgibt. In diesem Fall verbinden wir wie im Classic zwei DataItems (Customer / Customer Ledger Entry) miteinander. Zusätzlich dazu lege ich fest welche Felder ich im Layout nutzen möchte (für Andruck oder für die Sichtbarkeit eines druckbaren Elementes). Für die Entwicklung nutze ich Dynamics NAV 2016 mit Visual Studio 2015. Das Ganze könnte dann so aussehen: <img loading="lazy" decoding="async" class="alignnone wp-image-27 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_Name.jpg" alt="DataSet_Name" width="606" height="397" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_Name.jpg 606w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_Name-300x197.jpg 300w" sizes="auto, (max-width: 606px) 100vw, 606px" /> Wirft man einen Blick auf den Namen, dann fällt auf, dass ich nicht die eingefügte Beschreibung über das FieldMenü genutzt habe. Das würde nämlich normalerweise so aussehen: <img loading="lazy" decoding="async" class="alignnone size-full wp-image-28" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_Name2.jpg" alt="DataSet_Name2" width="570" height="46" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_Name2.jpg 570w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_Name2-300x24.jpg 300w" sizes="auto, (max-width: 570px) 100vw, 570px" /> Das mache ich aus den folgenden Gründen. Die Debitorentabelle ist vergleichbar mit der Kreditorentabelle. Wenn ich später aus meiner erstellten Debitorenstatistik eine Kreditorenstatistik machen möchte, dann müsste ich mein Dataset wieder neu aufbauen. Ebenfalls müsste ich Änderungen im Layout vornehmen. Daher halte ich mich an folgende Regeln: Vermeide den Tabellennamen im Feld „Data Source“ Vermeide einen zu spezifischen Namen im Feld „Name“ Hält man sich an diese Regel, kann man später aus einem Rechnungslayout ein Gutschriftslayout machen und lediglich die kleinen Änderungen innerhalb der beiden Belege bearbeiten. Das werde ich exemplarisch in einem späteren Beitrag an unserer Debitorenstatistik zeigen. Zusätzlich zu unseren übergebenen Feldern, müssen wir ebenfalls Captions (Bezeichnungen / Überschriften) übertragen. Dafür gibt es im RDLC drei Möglichkeiten und unterschiedliche Anwendungsfälle: IncludeCaption Eigenschaft im DataSet: Sollte genutzt werden, wenn der Bericht pro Ausführung immer nur in einer Sprache ausgeführt werden soll. Sollte genutzt werden, wenn die Feldcaption aus der Tabelle für dieses Feld genutzt werden soll. Wird einmal an das DataSet übergeben und steht dann dort als Parameter zur Verfügung. Labels (Ansicht -> Labels): Sollte genutzt werden, wenn der Bericht pro Ausführung immer nur in einer Sprache ausgeführt werden soll. Sollte genutzt werden, wenn man eine abweichende Caption im Vergleich zur Feldcaption angeben möchte oder für allgemeine Informationen (ReportCaption). Beispiel: Caption vom Feld „No.“ aus der Tabelle Customer ist „Nr.“ – Möchte ich nun, dass im Bericht „Kundennr.“ als Überschrift angezeigt wird, verwende ich ein Label anstatt „IncludeCaption“) Wird einmal an das DataSet übergeben und steht dann dort als Parameter zur Verfügung. Text Constants (Ansicht -> C/AL Globals -> Text Constants) / FIELDCAPTION / Variablen + Integration der Textkonstante in das Dataset: Die Textkonstanten, Variablen oder FIELDCaption im Dataset sind das Gegenstück zu den Labels oder IncludeCaption und sollten verwendet werden, wenn sich im Druck eines Beleges die Sprache Datensatz bezogen ändern kann. Hierbei ist zu berücksichtigen, dass Sie das Dataset durch Verwendung von Textkonstanten stark vergrößern. Klar es gibt auch die Möglichkeit, die Caption hart in die Textboxen im Layout zu hinterlegen. Das ist für mich aber keine Option. In meinem Fall lege ich nun zwei Labels an und löse den Rest über IncludeCaption. Wir haben in unserem Beispiel keinen Bedarf an Textkonstanten. Des Weiteren gilt: Umso kleiner das Dataset umso schneller läuft der Bericht. Um bei Labels CaptionML zu pflegen muss man dort die Eigenschaften öffnen. <img loading="lazy" decoding="async" class="alignnone wp-image-29" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_Labels.jpg" alt="DataSet_Labels" width="843" height="249" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_Labels.jpg 863w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_Labels-300x89.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_Labels-768x227.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_Labels-660x195.jpg 660w" sizes="auto, (max-width: 843px) 100vw, 843px" /> Mein Dataset sieht nun so aus: <img loading="lazy" decoding="async" class="alignnone wp-image-30 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_IncludeCaption.jpg" alt="DataSet_IncludeCaption" width="900" height="484" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_IncludeCaption.jpg 900w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_IncludeCaption-300x161.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_IncludeCaption-768x413.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_IncludeCaption-660x355.jpg 660w" sizes="auto, (max-width: 900px) 100vw, 900px" /> Nun kann man sich das Dataset mal anschauen. Dafür führe ich den Bericht einfach aus. Um das Dataset zu betrachten, brauche ich auch kein Layout. Ich möchte lediglich prüfen, ob mein DataSet vollständig ist und das die Informationen so übertragen werden, wie ich es benötige. Dafür öffnet man den Beleg und wählt über den weißen Pfeil im blauen Feld „Hilfe“ aus und „Info zu dieser Seite“. Es öffnet sich ein neues Fenster, welches der Zoom des Berichts darstellt. Dieses Fenster schließen wir wieder. Starte ich nun den Bericht in der Vorschau, dann kann ich mir das Dataset ansehen. <img loading="lazy" decoding="async" class="alignnone wp-image-31 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_Ansehen.jpg" alt="DataSet_Ansehen" width="464" height="582" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_Ansehen.jpg 464w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_Ansehen-239x300.jpg 239w" sizes="auto, (max-width: 464px) 100vw, 464px" /> In der geöffneten Seitenansicht, also wieder über den blauen Knopf „Hilfe“ und diesmal „Info zu diesem Bericht“ auswählen: <img loading="lazy" decoding="async" class="alignnone wp-image-32" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_Ansehen2.jpg" alt="DataSet_Ansehen2" width="772" height="469" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_Ansehen2.jpg 854w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_Ansehen2-300x182.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_Ansehen2-768x467.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_Ansehen2-660x401.jpg 660w" sizes="auto, (max-width: 772px) 100vw, 772px" /> Danach öffnet sich das DataSet: <img loading="lazy" decoding="async" class="alignnone wp-image-33 size-full" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_Ansehen3.jpg" alt="DataSet_Ansehen3" width="1388" height="774" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_Ansehen3.jpg 1388w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_Ansehen3-300x167.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_Ansehen3-768x428.jpg 768w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_Ansehen3-1024x571.jpg 1024w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/DataSet_Ansehen3-660x368.jpg 660w" sizes="auto, (max-width: 1388px) 100vw, 1388px" /> Hier sehen wir nun, das wir die Daten bekommen. Ich möchte kurz auf den Aufbau des Datasets eingehen: Jeder Kunde erzeugt mindestens 1 Zeile. Ausnahme: Wenn PrintOnlyIfDetail im DataItem „Customer“ auf Ja steht, dann werden Kunden ohne Posten ausgeblendet. Der erste Posten wird immer auch in der ersten Zeile zum jeweiligen Debitoren angezeigt. Das sehen wir sehr gut bei „Progessive Ho…“ Beim Kunden 10000 Möbel Meller KG gibt es mehr als einen Posten. In diesem Fall wiederholen sich die Information aus dem DataItem Customer für jeden Posten erneut. Das Dataset ist also eine große Zusammenführung unserer DataItems und kennt keine Abhängigkeiten mehr. Das bedeutet, wir erstellen in NAV unsere DataItem Struktur um diese beim Designen verwenden zu können. Die Logik, wann wie etwas gruppiert oder gedruckt werden soll, müssen wir im RDLC anhand der Datenbasis des Datasets selbst festlegen. Wie wir hier sehen können, werden Labels oder die Captions der Felder mit „IncludeCaption“ hier nicht angezeigt. Diese werden einmal übertragen und sind nicht Teil unserer Dataset-Struktur. Diese Felder stehen uns in Designer als Parameter zur Verfügung. Darauf gehe ich das nächste Mal ein, wenn ich das Layout und die Beschaffenheit der Elemente etwas näher erläuterte. Ebenfalls sehen wir hier, dass zu jedem Decimalfeld auch eine Formatierung übertragen wird. Diese Formatierung basiert auf der Vorgabe des Tabellenfeldes. In den Einstellungen des Feldes im jeweiligen DataItem kann die Formatierung dann auch nochmal geändert werden. Bei Fragen schreibt mir einen Kommentar. Ich versuche die Fragen nach meinen zeitlichen Möglichkeiten zu beantworten. The post RDLC für NAV Entwickler #1 – Allgemeine Informationen & das Dataset first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
Ich werde in Zukunft über Dynamics NAV bloggen. Fühlt Euch frei meinem RSS-Feed zu abonnieren oder mich zu kontaktieren. Dieser Blog wurde am 14.02.2016 ins Leben gerufen. Daher wird der Inhalt der Seite noch mit Themen gefüllt, die mich in der Zukunft bewegen und die ich mit Euch teilen möchte. The post Hello World first appeared on Robert's Dynamics NAV/BC Entwickler Blog.
<img loading="lazy" decoding="async" class="size-medium wp-image-19 alignleft" src="http://robert-dynamicsnav.de/wp-content/uploads/2016/02/gardener-1015584_960_720-300x300.jpg" alt="Hello" width="300" height="300" srcset="https://robert-dynamicsnav.de/wp-content/uploads/2016/02/gardener-1015584_960_720-300x300.jpg 300w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/gardener-1015584_960_720-150x150.jpg 150w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/gardener-1015584_960_720-660x660.jpg 660w, https://robert-dynamicsnav.de/wp-content/uploads/2016/02/gardener-1015584_960_720.jpg 720w" sizes="auto, (max-width: 300px) 100vw, 300px" />Ich werde in Zukunft über Dynamics NAV bloggen. Fühlt Euch frei meinem RSS-Feed zu abonnieren oder mich zu kontaktieren. Dieser Blog wurde am 14.02.2016 ins Leben gerufen. Daher wird der Inhalt der Seite noch mit Themen gefüllt, die mich in der Zukunft bewegen und die ich mit Euch teilen möchte. The post Hello World first appeared on Robert's Dynamics NAV/BC Entwickler Blog.