Redis
 sql >> Datenbank >  >> NoSQL >> Redis

ServiceStack.Net Redis:Speichern verwandter Objekte im Vergleich zu verwandten Objekt-IDs

Anstatt viele andere Dokumentationen, die es in freier Wildbahn gibt, erneut zu hashen, liste ich ein paar auf, um Hintergrundinformationen zum Redis-Client von Redis + ServiceStack zu erhalten:

  • Was Sie beim Entwerfen einer NoSQL Redis-Anwendung beachten sollten
  • Entwerfen einer NoSQL-Datenbank mit Redis
  • Allgemeiner Überblick über Redis und .NET
  • Schemalose Versionierung und Datenmigrationen mit C# Redis Client

Es gibt keine Magie - Redis ist eine leere Leinwand

Zunächst möchte ich darauf hinweisen, dass die Verwendung von Redis als Datenspeicher nur eine leere Leinwand bietet und kein Konzept verwandter Entitäten an sich hat. Das heißt, es bietet nur Zugriff auf verteilte comp-sci-Datenstrukturen. Wie Beziehungen gespeichert werden, hängt letztendlich vom Client-Treiber (d. h. ServiceStack C# Redis Client) oder dem App-Entwickler ab, indem die primitiven Datenstrukturoperationen von Redis verwendet werden. Da alle wichtigen Datenstrukturen in Redis implementiert sind, haben Sie grundsätzlich völlige Freiheit, wie Sie Ihre Daten strukturieren und speichern möchten.

Überlegen Sie, wie Sie Beziehungen im Code strukturieren würden

Der beste Weg, darüber nachzudenken, wie man Dinge in Redis speichert, besteht also darin, die Art und Weise, wie Daten in einer RDBMS-Tabelle gespeichert werden, völlig außer Acht zu lassen und darüber nachzudenken, wie sie in Ihrem Code gespeichert werden, d. h. die Verwendung der integrierten C#-Erfassungsklassen im Speicher - die Redis im Verhalten mit ihren serverseitigen Datenstrukturen widerspiegelt.

Obwohl es kein Konzept verwandter Entitäten gibt, ist die integrierte Set von Redis und SortedSet Datenstrukturen bieten die ideale Möglichkeit, Indizes zu speichern. Z.B. Set von Redis Die Sammlung speichert nur maximal 1 Vorkommen eines Elements. Dies bedeutet, dass Sie sicher Elemente/Schlüssel/IDs hinzufügen können und sich nicht darum kümmern, ob das Element bereits vorhanden ist, da das Endergebnis das gleiche sein wird, wenn Sie es 1 oder 100 Mal aufgerufen haben - dh es ist idempotent und letztendlich bleibt nur 1 Element darin gespeichert der Satz. Ein häufiger Anwendungsfall besteht also darin, beim Speichern eines Objektdiagramms (aggregierter Stamm) die untergeordneten Entitäts-IDs (auch bekannt als Fremdschlüssel) jedes Mal, wenn Sie das Modell speichern, in einem Satz zu speichern.

Ihre Daten visualisieren

Für eine gute Visualisierung, wie Entitäten in Redis gespeichert werden, empfehle ich die Installation der Redis Admin-Benutzeroberfläche, die gut mit dem C# Redis-Client von ServiceStack funktioniert, da sie die unten stehende Schlüsselbenennungskonvention verwendet, um eine schöne hierarchische Ansicht bereitzustellen und Ihre eingegebenen Entitäten zusammen zu gruppieren (trotz aller Schlüssel im selben globalen Schlüsselraum vorhanden).

Um eine Entität anzuzeigen und zu bearbeiten, klicken Sie auf Bearbeiten Link, um die interne JSON-Darstellung der ausgewählten Entität anzuzeigen und zu ändern. Hoffentlich können Sie bessere Entscheidungen darüber treffen, wie Sie Ihre Modelle entwerfen, sobald Sie sehen können, wie sie gespeichert werden.

Wie POCO / Entitäten gespeichert werden

Der C# Redis-Client funktioniert mit allen POCOs, die einen einzigen Primärschlüssel haben – der standardmäßig als Id erwartet wird (obwohl diese Konvention mit ModelConfig überschrieben werden kann). Im Wesentlichen werden POCOs in Redis als serialisiertes JSON mit sowohl dem typeof(Poco).Name gespeichert und die Id verwendet, um einen eindeutigen Schlüssel für diese Instanz zu bilden. Beispiel:

urn:Poco:{Id} => '{"Id":1,"Foo":"Bar"}'

POCOs im C#-Client werden herkömmlicherweise mit dem schnellen Json Serializer von ServiceStack serialisiert, wobei nur Eigenschaften mit öffentlichen Gettern serialisiert werden (und öffentliche Setter, um wieder deserialisiert zu werden).

Standardwerte können mit [DataMember] überschrieben werden attrs, aber nicht empfohlen, da es Ihre POCOs hässlich macht.

Entitäten werden blobbed

Da Sie also wissen, dass POCOs in Redis nur Blobs sind, möchten Sie nur nicht aggregierte Stammdaten auf Ihren POCOs als öffentliche Eigenschaften behalten (es sei denn, Sie möchten absichtlich redundante Daten speichern). Eine gute Konvention besteht darin, Methoden zum Abrufen der zugehörigen Daten zu verwenden (da sie nicht serialisiert werden), aber auch Ihrer App mitzuteilen, welche Methoden Remoteaufrufe zum Lesen von Daten durchführen.

Daher die Frage, ob der Feed sollte beim Benutzer gespeichert werden ist, ob es sich um nicht aggregierte Stammdaten handelt, d. h. ob Sie auf die Benutzer-Feeds außerhalb des Kontexts des Benutzers zugreifen möchten oder nicht? Wenn nein, verlassen Sie die List<Feed> Feeds -Eigenschaft auf dem User Typ.

Benutzerdefinierte Indizes verwalten

Wenn Sie jedoch alle Feeds unabhängig voneinander zugänglich halten möchten, z. B. mit redisFeeds.GetById(1) dann möchten Sie es außerhalb des Benutzers speichern und einen Index pflegen, der die beiden Entitäten verknüpft.

Wie Sie bemerkt haben, gibt es viele Möglichkeiten, Beziehungen zwischen Entitäten zu speichern, und wie Sie dies tun, ist weitgehend eine Frage der Präferenz. Für die untergeordnete Entität in einem parent>child Beziehung möchten Sie immer die ParentId speichern mit der untergeordneten Entität. Für den Parent können Sie entweder eine Sammlung von ChildIds speichern mit dem Modell und führen Sie dann einen einzigen Abruf für alle untergeordneten Entitäten durch, um das Modell zu rehydrieren.

Eine andere Möglichkeit besteht darin, den Index außerhalb des übergeordneten dto in einem eigenen Set zu verwalten für jede übergeordnete Instanz. Einige gute Beispiele dafür finden sich im C#-Quellcode der Redis StackOverflow-Demo, wo die Beziehung von Users > Questions und Users > Answers wird gespeichert in:

idx:user>q:{UserId} => [{QuestionId1},{QuestionId2},etc]
idx:user>a:{UserId} => [{AnswerId1},{AnswerId2},etc]

Obwohl der C# RedisClient Unterstützung für eine standardmäßige Parent/Child-Konvention über seine TParent.StoreRelatedEntities(), TParent.GetRelatedEntities<TChild>() enthält und TParent.DeleteRelatedEntities() APIs, bei denen hinter den Kulissen ein Index verwaltet wird, der wie folgt aussieht:

ref:Question/Answer:{QuestionId} => [{answerIds},..]

Tatsächlich sind dies nur einige Ihrer möglichen Optionen, bei denen es viele verschiedene Möglichkeiten gibt, dasselbe Ziel zu erreichen, und bei denen Sie auch die Freiheit haben, Ihre eigenen zu würfeln.

Die schemalosen, lockeren Freiheiten von NoSQL sollten angenommen werden, und Sie sollten sich keine Sorgen machen, einer starren, vordefinierten Struktur zu folgen, mit der Sie möglicherweise vertraut sind, wenn Sie ein RDBMS verwenden.

Zusammenfassend lässt sich sagen, dass es keinen wirklichen richtigen Weg gibt um Daten in Redis zu speichern, z.B. Der C#-Redis-Client trifft einige Annahmen, um eine High-Level-API um POCOs herum bereitzustellen, und er blobt die POCOs in den binärsicheren Zeichenfolgenwerten von Redis – obwohl es andere Clients gibt, die es vorziehen, die Eigenschaften einer Entität stattdessen in Redis-Hashes (Wörterbüchern) zu speichern . Beides wird funktionieren.