NDO 4.0 ist da

Voraussetzungen:

  • Visual Studio 2017 >= 15.7.6
  • .NET Framework >= 4.6.1
  • .NET Standard = 2.0
  • Ihre Anwendungen müssen .NET Framework 4.5.2 oder höher unterstützen

Testen Sie NDO 4.0 jetzt

Installieren Sie einfach das Nuget-Package ndo.dll. Die NDO-Provider sind ebenfalls auf Nuget. Ihre Namen sind ndo.sqlserver, ndo.mysql, etc., also immer ndo.<ProviderName>. Sie können NDO und die Provider auch vom NDO-Konfigurationsdialog aus laden.

Abfragen

NDO hat nun einen echten Parser für seine Abfragesprache NDOql. Aufgrund der Ähnlichkeit zwischen NDOql und den WHERE-Klauseln in SQL, verwendete NDO einen simplen Mechanismus zur Textersetzung, um NDOql in SQL zu übersetzen. Diese simple Technik brachte erhebliche Einschränkungen mit sich. Es war nahezu unmöglich, die Fähigkeiten der Abfragesprache an die neuen Erfordernisse der täglichen Entwicklungsarbeit anzupassen. Nun gibt es einen LL1-Parser für NDOql, der auf einer attributierten Grammatik basiert. Eigentlich begannen wir die Arbeit an dem Parser schon 2011, aber wir fanden erst jetzt die Zeit, die Arbeit zu vollenden.

Breaking Changes

Wir haben die untypisierte Query-Klasse aus NDO entfernt. Wenn Sie Code wie diesen benutzen:

Query q = pm.NewQuery(typeof(Employee), "name={0}");

Das wird nicht kompilieren. Als einen Migrationspfad gibt es das Interface IQuery:

IQuery q = pm.NewQuery(typeof(Employee), "name={0}");

Hinter diesem Interface arbeitet eine NDOQuery<T>. Das Interface existiert nur zum Zweck, alten Code schnell lauffähig zu machen. Wir empfehlen aber, für Abfragen Linq zu verwenden.

Linq support

Einer der Hauptgründe, um die Query Engine zu ändern, war der Linq-Support. NDO 3.0 hatte ja schon einen Linq-Support für einfache Abfragen. Aber wir wollten Linq für alle Abfragesituationen nutzen, die in der Praxis so eintreten können. Der Vorteil von Linq ist, dass der Compiler die Abfragen überprüft.

Nun können Sie Abfragen wie die folgende schreiben:

var idValues = new[]{1,2,3,4,5};
var vt = pm.Objects<Employee>().Where(e=>e.Travels[Any.Index].Countries.Oid().In(idValues));

Das ergibt folgenden Sql-Code:

SELECT … FROM [Employee]
INNER JOIN [Travel] ON [Employee].[ID] = [Travel].[IDEmployee]
INNER JOIN [relCountryTravel] ON [Travel].[ID] = [relCountryTravel].[IDTravel]
WHERE [relCountryTravel].[IDCountry] IN (1, 2, 3, 4, 5)

Wir haben eine Menge an Unit Tests geschrieben, um den Linq-Support so mächtig, wie NDOql zu gestalten. Es sollte kaum mehr Gründe geben, NDOQuery statt Linq zu verwenden. Aber die Klasse NDOQuery ist der Kern der Query Engine. Linq-Expressions werden in NDOql transformiert, und dann mit Hilfe von NDOQuery<T> ausgeführt.

Query Helpers

In der Vergangenheit erzeugte der NDO-Enhancer verschachtelte QueryHelper-Klassen als Members der persistenten Klassen, um eine Art Compiler-Validierung der Identifier bei Abfragen zu ermöglichen. Mit Linq ist diese Validierung nicht mehr nötig. Wenn Sie in alten Projekten QueryHelper genutzt haben, werden diese nicht mehr funktionieren und Sie müssen Ihren Code ändern. Wir haben die QueryHelpers entfernt, weil Visual Studio ohnehin keinen Intellisense-Support dafür anbietet.

.ndoproject…

In früheren Versionen gab es eine große Herausforderung für NDO-Entwickler: Die Verwaltung der .ndoproj-Dateien. NDO trug alle Referenzen eines Projekts in dieser Datei ein und der Enhancer versuchte, die Dateien zu analysieren. Man konnte die Analyse einzelner Dateien dadurch verhindern, indem man der jeweiligen Referenz das Attribut CheckThisDLL gab, und den Wert des Attributs auf false setzte. Aber jede Änderung an Projektreferenzen führte zu Änderungen in der .ndoproj-Datei, die zu Konflikten in der Source-Code-Kontrolle führte.

Die Lösung ist einfach: Wir tragen keine Assemblies in der .ndoproj-Datei mehr ein, wenn sie nicht persistente Klassen enthalten. Und im NDO-Konfigurationsdialog lässt sich einstellen, welche dieser DLLs analysiert werden sollen. Neue Assemblies werden gleich einmal mit dem Attribut CheckThisDLL="False" eingetragen. Diese Lösung reduziert die Anzahl an Änderungen, die sich an der .ndoproj-Datei ergeben, dramatisch.

Diese Verbesserung hat ihren Preis: Sie müssen zumindest für ein Assembly in der UI die Analyse anschalten, sonst bekommen Sie eine leere NDOMapping.xml-Datei.

Und wo wir gerade bei der NDOMapping.xml sind: Wenn Sie den Namen der NDOMapping.xml aus dem Konfigurationsdialog löschen, erzeugt NDO eine Datei, die sich aus dem Projektnamen ergibt:

<Projektname>.ndomapping.xml

NDO findet Dateien mit diesem Namen ebenso, wie die NDOMapping.xml.

NDO providers

Alle Provider sind nun in ihrer eigenen Provider-DLL, die mit einem Nuget-Package geladen wird. Das gilt auch für den Sql Server. Und es gibt separate DLLs für die UI zum Anlegen von Connection Strings und neuen Datenbanken. Diese separaten DLLs werden von der Visual Studio Extension benutzt. Wenn Sie einen bestimmten Provider auswählen, können Sie diesen Provider direkt von Nuget laden, indem Sie auf einen Knopf drücken.

.NET Core / .NET Standard

Microsoft hat einen unglaublichen Job bei der Entwicklung von .NET Core hingelegt. Insbesondere .NET Standard ist ein hervorragender Weg, um sowohl für .NET Framework also auch für .NET Core zu entwickeln. NDO 4 unterstützt .NET Standard 2.0. So können Sie .NET Core-Projekte mit Referenzen auf .NET Standard-DLLs anlegen, die Ihre persistenten Klassen enthalten. Die NDO-DLLs stehen für .NET 4.5.2 und .NET Standard 2.0 zur Verfügung. Nuget sucht für Ihr Projekt die richtige aus.

Dependency Injection

NDO verwendet eine einfache DI-Container-Implementierung für seine internen Zwecke. Damit können Sie Ihre eigenen Klassen und Interfaces registrieren und auf diese Weise Ihre persistenten Klassen mit DI-Konstruktoren ausstatten.

Sie können Klassen und Instanzen auf statischer Ebene registrieren, sodass die Registrierungen währen der gesamten Laufzeit der Anwendung genutzt werden können. Und Sie können Klassen und Instanzen bei einem Container registrieren, der an die Laufzeit des PersistenceManagers gekoppelt ist. Sobald der PersistenceManager geschlossen wird, erlöschen die Registrierungen. Das ist sehr praktisch für Web-Anwendungen, wo Registrierungen von Instanzen nur für die Dauer eines Requests gültig bleiben sollen.

Wenn Sie persistente Klassen anlegen, löst NDO automatisch die Abhängigkeiten auf. Sie können dazu pm.CreateObject<T> nutzen, oder einfach ein Objekt Ihrer persistenten Klassen vom Container auflösen lassen.

Die DI-Implementierung wurde den Unity-Containern nachempfunden, weil anfangs Unity von NDO verwendet wurde. Aber Unity zeigte in manchen Situationen ein seltsames Verhalten, sodass wir eine eigene Implementierung vorzogen. Diese Implementierung ist viel schlanker und unterstützt nur einen Teil der Funktionalität von Unity.

.NET Standard 2.1

Beachten Sie: .NET Standard-Dlls in Versionen > 2.0 können mit NDO nicht verwendet werden, weil der NDO-Enhancer eine .NET Framework-Anwendung ist. Der Enhancer lädt das Assembly, das er analysieren muss, in eine AppDomain. .NET Standard 2.1-Assemblies können aber nur in .NETCore apps >= V. 3 geladen werden.

Es ist geplant, den Enhancer irgendwann mit .NET Core zu entwickeln. Das wird aber nicht vor .NET 5.0 der Fall sein.

Gegenwärtig gibt es keinen Grund, warum Assemblies mit persistenten Klassen für .NET Standard > 2.0 entwickelt werden sollten.