Was ist der beste Weg, um mehrere Typen in einer RavenDB-Sammlung zu speichern / abzufragen?

8

Ich entwerfe ein Protokollierungssystem, das seine Protokolleinträge in RavenDB speichert, und für dieses spezielle System möchte ich Dokumente speichern und später abfragen, die unterschiedliche Datenstrukturen haben, die auf dem Typ des protokollierten Ereignisses basieren. Betrachten Sie die folgenden Ereignisse, die ich protokollieren möchte:

  1. Der Benutzer meldet sich an - Speichern Sie die Benutzer-ID
  2. Benutzer löscht eine Datei - Speichern Sie die UserID und den Dateinamen, der gelöscht wird

Ich habe ein paar verschiedene Möglichkeiten, wie ich hier hingehen kann ...

Option A. Erstellen Sie zwei völlig verschiedene Typen

%Vor%

Dieser Ansatz führt zu zwei verschiedenen Sammlungen in RavenDB, die leicht abgefragt werden können. Das Abrufen einer Vereinigung aller Protokolleinträge erfordert jedoch mehrere Abfragen und mehrere Roundtrips zum Server - einen für die LoginEvents und einen zweiten für die FileDeleteEvents. Mit nur zwei Ereignistypen macht das keinen großen Unterschied, aber das Problem wird mit der Anzahl der Ereignistypen erheblich schlimmer.

Option B. Erstellen Sie eine Basisklasse und leiten Sie daraus ab

%Vor%

Ich habe diesen Ansatz versucht, aber RavenDB scheint Dokumente nach ihren tatsächlichen Typen zu speichern und abzufragen, nicht nach ihren Gattentypen - wenn ich Query<Event>().ToArray() gemacht habe, habe ich null Ergebnisse erhalten. Um die Dokumente zurück zu bekommen, müsste ich nach ihren individuellen Typen fragen, was dies effektiv der obigen Option A entspricht.

Option C. Erstellen Sie verschiedene Eigenschaftsklassen

%Vor%

Bei diesem Ansatz speichern wir immer einen Eintrag vom Typ Event, aber wir füllen seine Info-Eigenschaft mit der entsprechenden Info-Klasse, die Details zum Ereignistyp enthält. Zunächst schien diese Option die beste zu sein, da sie alle Protokolleinträge in einer einzigen Ereignissammlung speichert und die Abfrage der gesamten Sammlung erleichtert. Nehmen wir an, ich möchte nur die FileDelete-Ereignisse, bei denen der Dateiname "test.txt" ist. Dies wird ein wenig schwierig.

Im Folgenden wird beispielsweise ein etwas unklarer Fehler bezüglich des nicht indizierten Felds "Dateiname" angezeigt:

%Vor%

Das folgende gibt, abgesehen davon, dass es nicht das ist, was ich will, null Ergebnisse zurück:

%Vor%

Tatsächlich liefert die folgende Projektion, eine gemäß der Dokumentation unterstützte Operation, nicht einmal den erwarteten Typ, sondern nur eine Reihe seltsamer Zwischenergebnisse, die keinen Sinn ergeben:

%Vor%

Obwohl diese Option aus Datenspeicherperspektive wahrscheinlich gut ist, schlägt sie aus der Perspektive der Abfragefähigkeit fehl. (Angenommen, ich baue die richtige Abfrage - es könnte einen anderen Weg geben, den ich nicht in Betracht ziehe).

Option D. Erstellen Sie eine riesige Ereignisklasse mit allen möglichen Eigenschaften

%Vor%

Dieser Ansatz ist zwar aus Speicherperspektive ein wenig verschwenderisch, aus der Frage der Abfragefreundlichkeit jedoch trivial. Das Problem tritt auf, wenn Sie weitere Arten von Ereignissen hinzufügen, die Sie protokollieren möchten - dann beginnt die Anzahl der Eigenschaften zu steigen.

Option E. Vergessen Sie RavenDB und verwenden Sie Entity Framework + Sql

Ich kann das ziemlich trivial machen und effizient nach EFs Tabelle-pro-Vererbungsmuster suchen. Die Kehrseite dieses Ansatzes ist, dass Sql für dieses Problem ein ernsthafter Overkill ist - wir brauchen keine Datenkonsistenz und keine andere Strenge, die relationale Systeme bieten. Und meiner Erfahrung nach sind Sql-Inserts viel langsamer als die Dokumentenspeicherung in RavenDB (eine wichtige Überlegung für ein Protokollierungssystem).

Also, da sind die Optionen ... was denkst du? Gibt es etwas, was ich vermisst habe?

Möglicherweise verwandt: Sammlungsname in RavenDB angeben

    
Mike 25.02.2012, 06:22
quelle

3 Antworten

5

Der "offizielle" Weg zur Lösung dieses Problems scheint ein polymorpher Index zu sein: Ссылка

Hier ist ein Blogeintrag, der diesen Ansatz im Detail diskutiert: Ссылка

Es gibt auch ein Video hier: Ссылка

    
Mike 25.02.2012, 22:07
quelle
2

Geh mit der Basisklasse-Sache. Der Trick besteht darin, Polymorphie zu verwenden und allen konkreten Typen den gleichen Typ-Tag-Namen zu geben. Jetzt können Sie sie leicht abfragen, da sie sich in derselben Sammlung befinden.

%Vor%     
Daniel Lang 25.02.2012 12:58
quelle
0

Basisklasse Versuchen Sie immer den richtigen Oop zu verwenden.

Sie müssen angeben, dass alle Unterklassen in derselben Sammlung gespeichert werden sollen

    
jgauffin 25.02.2012 06:26
quelle