MongoDB

MongoDB Driver for C# in 3 Schritten zukunftssicher einstellen

MongoDB und auch der Driver for C# sind mittlerweile schon eine gute Zeit am Markt. Da ist es nicht verwunderlich, dass manche Komponenten durch neuere Version ersetzt werden. Um Breaking Changes bei bestehenden Projekten zu vermeiden, verwendet MongoDB jedoch standardmäßig meistens die Vorgängerversion. Um ein Projekt zukunftssicher aufzusetzen, sollte jedoch von vorne herein auf die neuen Versionen aufsetzen. Dies erreicht man, indem man direkt beim Start der Applikation bzw. dem Aufbauen der Verbindung zu MongoDB folgende Schritte erledigt:

1. Die Serialisierung von Guid-Werten konfigurieren

Guids wurden früher in MongoDB als Binary mit Subtype 3 (UUID old) abgespeichert. Leider gab es Unterschiede zwischen den Drivern, so dass eine Java-Applikation die Daten anders abgespeichert hat als eine C#-Applikation. Da dies in einigen Fällen problematisch werden kann, hat man sich entschieden, den neuen Subtype 4 (UUID) einzuführen und die Daten konsistent zwischen den Drivern abzulegen. Bisher (Driver Version 2.17) ist jedoch die Verwendung von Subtype 3 im Driver for C# noch die Standardeinstellung. Da die neue Version der Serialisierung standardmäßig den Subtype 4 verwendet und insgesamt mehr Freiheiten bietet, ist es also sinnvoll, von vorne herein auf diese zu setzen und den Driver entsprechend einzustellen. Dies ist mit folgendem Befehl möglich:

BsonDefaults.GuidRepresentationMode = GuidRepresentationMode.V3;

Bitte lassen Sie sich von der verwendeten Versionsnummer V3 des GuidRepresentationMode nicht irritieren - V3 verwendet standardmäßig den Subtype 4. Dieser Opt-In zu Subtype 4 sollte möglichst früh in der Anwendung erfolgen. Sollte es einzelne Eigenschaften geben, die noch Subtype 3 verwenden, kann dies direkt an der Eigenschaft konfiguriert werden, z.B. über ein Attribute:

public class MyDocument
{
  // ...
  [BsonGuidRepresentation(GuidRepresentation.Standard)]
    public Guid MySubtype3Guid { get; set; }
}

Details zur Serialisierung von Guids finden Sie in der Dokumentation des Drivers.

2. Den LINQ-Provider wählen

In den letzten Versionen hat der MongoDB Driver for C# einen neuen LINQ-Provider erhalten (V3). Dieser erweitert die Möglichkeiten, die mit LINQ zur Verfügung stehen im Vergleich zur Vorgängerversion. Neue Anwendungen oder Anwendungen, die bei LINQ-Abfragen an Limits stoßen, sollten also auf der neuen Version aufsetzen - “LINQ3 is production-ready”. Außerdem kann man für die Zukunft davon ausgehen, dass Erweiterungen vor allem in der neuen Version vorgenommen werden. Die Auswahl des LINQ-Providers wird über die Einstellungen des Clients erledigt und betrifft alle Abfragen, die über diesen Client laufen:

var connectionString = "...";
var settings = MongoClientSettings.FromConnectionString(connectionString);
settings.LinqProvider = LinqProvider.V3;
var client = new MongoClient(settings);

3. Mapping konfigurieren

Zumeist werden ClassMaps automatisch erstellt oder deklarativ über Attribute definiert. In diesem Fall konfiguriert der Driver for C# die Zuordnung von .NET POCOs auf MongoDB Dokumente weitgehend automatisch - und das zum richtigen Zeitpunkt. Will man die POCOs jedoch frei von MongoDB-Attributen halten und erstellt ClassMaps daher über BsonClassMap.RegisterClassMap<T>, muss man sicherstellen, dass dies rechtzeitig - und zwar vor der ersten Abfrage auf die Dokumente - passiert. Dies ist insbesondere dann wichtig, wenn Klassenhierarchien in MongoDB abgelegt werden und der Driver beim Deserialisieren herausfinden muss, auf welche Klasse der Wert des Type-Discriminators (_t-Eigentschaft im Dokument) gemappt werden soll. Falls ein Repository den Zugriff auf einen Dokumententyp regelt, kann beispielsweise der statische Konstruktur als eine einfache Möglichkeit genutzt werden:

public class MyDocumentRepository {
  static MyDocumentRepository()
  {
    BsonClassMaps.RegisterClassMap<MyDocument>(cm =>
    {
      cm.AutoMap();
      cm.MapMember(m => m.Title).SetElementName("t");
    });
  }
}

Eine Entscheidung hinsichtlich der ClassMaps kann die “Toleranz” des Drivers gegenüber zukünftigen Änderungen an der Datenbank deutlich erhöhen. Über das Attribute BsonIgnoreExtraElements bzw. cm.SetIgnoreExtraElements(true); kann man Fehlermeldungen vermeiden, die ausgelöst werden, wenn das MongoDB-Dokument Eigenschaften enthält, die dem Driver för C# nicht bekannt sind. Sofern man nicht extra-strikt sein will, was die Datenstrukturen angeht, empfiehlt es sich, diese Einstellung direkt zu wählen, um oft überflüssige Fehler zur Laufzeit auszuschließen.

Auch die Registrierung der Konventionen, die beim Mapping zum Einsatz kommen, sollte am Anfang der Anwendung erfolgen. Will man beispielsweise alle Eigenschaften in Camel-Case-Schreibweise in MongoDB ablegen, kann man eine entsprechende Konvention angeben, so dass nicht jeder einzelne Eigenschaftsname angepasst werden muss:

var pack = new ConventionPack();
pack.Add(new CamelCaseElementNameConvention());
ConventionRegistry.Register(
    "CamelCaseElementNameConvention",
    pack,
    t => t.Namespace.StartsWith(typeof(MyNamespace.MyRepository).Namespace + "."));

Dieser Code stellt sicher, dass alle Typen im Namespace des Repositories die neue Konvention verwenden. Details zu den Konventionen sind in der Dokumentation zu finden.

Fazit

Diese drei einfachen Schritte legen eine gute Basis für den Zugriff auf MongoDB aus einer .NET-Applikation heraus. Ihre Projekte sind zukunftssicher aufgesetzt und es ist von vorne herein sichergestellt, dass Daten wunschgemäß serialisiert werden. Läuft ein LINQ-Statement einmal nicht so wie geplant, weiß man genau, auf welcher Basis man aufgesetzt hat und verliert keine Zeit bei der Fehlersuche, etwa weil in einem Projekt noch ein alter LINQ-Provider eingestellt ist.

In diesem Sinne: auf einen guten Start ins MongoDB-Projekt mit C#.


MongoDB NoSql MongoDB Driver for C#
Markus Wildgruber
Markus Wildgruber

Geschäftsführer

  • CloudArchitect
  • DeveloperCoach
  • DotNet
  • MongoDB
  • Angular