Redis
 sql >> Base de données >  >> NoSQL >> Redis

ServiceStack.Net Redis :stockage d'objets associés par rapport aux identifiants d'objets associés

Plutôt que de re-hacher beaucoup d'autres documentations disponibles dans la nature, je vais en énumérer quelques-unes pour obtenir des informations générales sur le client Redis de Redis + ServiceStack :

  • À quoi penser lors de la conception d'une application NoSQL Redis
  • Concevoir une base de données NoSQL avec Redis
  • Présentation générale de Redis et .NET
  • Gestion des versions sans schéma et migrations de données avec le client C# Redis

Il n'y a pas de magie - Redis est une toile vierge

Tout d'abord, je tiens à souligner que l'utilisation de Redis en tant que magasin de données fournit simplement une toile vierge et n'a aucun concept d'entités associées en soi. c'est-à-dire qu'il fournit simplement un accès aux structures de données comp-sci distribuées. La manière dont les relations sont stockées dépend en fin de compte du pilote client (c'est-à-dire ServiceStack C# Redis Client) ou du développeur de l'application, en utilisant les opérations de structure de données primitives de Redis. Étant donné que toutes les principales structures de données sont implémentées dans Redis, vous disposez d'une totale liberté quant à la manière dont vous souhaitez structurer et stocker vos données.

Pensez à la façon dont vous structureriez les relations dans le code

Donc, la meilleure façon de penser à la façon de stocker des éléments dans Redis est de ne pas tenir compte de la façon dont les données sont stockées dans une table RDBMS et de réfléchir à la façon dont elles sont stockées dans votre code, c'est-à-dire en utilisant les classes de collection C# intégrées en mémoire - que Redis reflète dans le comportement avec leurs structures de données côté serveur.

Bien qu'il n'ait pas de concept d'entités associées, le Set intégré de Redis et SortedSet les structures de données constituent le moyen idéal pour stocker des index. Par exemple. Ensemble de Redis collection ne stocke qu'un maximum de 1 occurrence d'un élément. Cela signifie que vous pouvez y ajouter en toute sécurité des éléments/clés/identifiants sans vous soucier de savoir si l'élément existe déjà car le résultat final sera le même si vous l'avez appelé 1 ou 100 fois - c'est-à-dire qu'il est idempotent et qu'il ne reste finalement qu'un seul élément stocké dans l'ensemble. Ainsi, un cas d'utilisation courant est lorsque le stockage d'un graphique d'objets (racine agrégée) consiste à stocker les ID d'entité enfant (alias clés étrangères) dans un ensemble chaque fois que vous enregistrez le modèle.

Visualiser vos données

Pour une bonne visualisation de la façon dont les entités sont stockées dans Redis, je recommande d'installer l'interface utilisateur d'administration Redis qui fonctionne bien avec le client C # Redis de ServiceStack car il utilise la convention de dénomination des clés ci-dessous pour fournir une belle vue hiérarchique, regroupant vos entités typées ensemble (malgré toutes les clés existant dans le même espace de clés global).

Pour afficher et modifier une entité, cliquez sur Modifier link pour voir et modifier la représentation JSON interne de l'entité sélectionnée. J'espère que vous serez en mesure de prendre de meilleures décisions sur la façon de concevoir vos modèles une fois que vous aurez vu comment ils sont stockés.

Comment les POCO/entités sont stockées

Le client C# Redis fonctionne avec tous les POCO qui ont une seule clé primaire - qui par défaut devrait être Id (bien que cette convention puisse être remplacée par ModelConfig). Essentiellement, les POCO sont stockés dans Redis en tant que JSON sérialisé avec à la fois le typeof(Poco).Name et l'Id utilisé pour former une clé unique pour cette instance. Ex :

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

Les POCO dans le client C # sont sérialisés de manière conventionnelle à l'aide du sérialiseur Json rapide de ServiceStack, où seules les propriétés avec des getters publics sont sérialisées (et les setters publics doivent être désérialisés).

Les valeurs par défaut peuvent être remplacées par [DataMember] attrs mais déconseillé car il enlaidit vos POCO.

Les entités sont blobées

Donc, sachant que les POCO dans Redis sont simplement blobés, vous souhaitez uniquement conserver les données racine non agrégées sur vos POCO en tant que propriétés publiques (sauf si vous souhaitez volontairement stocker des données redondantes). Une bonne convention consiste à utiliser des méthodes pour récupérer les données associées (car elles ne seront pas sérialisées), mais indique également à votre application quelles méthodes effectuent des appels à distance pour lire les données.

Donc, la question de savoir si le Flux devrait être stocké avec l'utilisateur est-ce qu'il s'agit ou non de données racine non agrégées, c'est-à-dire si vous souhaitez ou non accéder aux flux des utilisateurs en dehors du contexte de l'utilisateur ? Si non, laissez la List<Feed> Feeds propriété sur l'User saisir.

Gestion des index personnalisés

Si toutefois vous souhaitez garder tous les flux accessibles indépendamment, c'est-à-dire avec redisFeeds.GetById(1) alors vous voudrez le stocker en dehors de l'utilisateur et maintenir un index reliant les 2 entités.

Comme vous l'avez remarqué, il existe de nombreuses façons de stocker les relations entre les entités et la façon dont vous le faites est en grande partie une question de préférence. Pour l'entité enfant dans un parent>enfant relation, vous voudriez toujours stocker le ParentId avec l'entité enfant. Pour le parent, vous pouvez soit choisir de stocker une collection de ChildIds avec le modèle, puis effectuez une seule extraction pour toutes les entités enfants afin de réhydrater le modèle.

Une autre façon consiste à maintenir l'index en dehors du dto parent dans son propre Set pour chaque instance parent. Quelques bons exemples de cela se trouvent dans le code source C# de la démo Redis StackOverflow où la relation de Users > Questions et Users > Answers est stocké dans :

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

Bien que le C# RedisClient inclut la prise en charge d'une convention parent/enfant par défaut via son TParent.StoreRelatedEntities(), TParent.GetRelatedEntities<TChild>() et TParent.DeleteRelatedEntities() API où un index est maintenu en arrière-plan qui ressemble à :

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

En fait, ce ne sont là que quelques-unes de vos options possibles, où il existe de nombreuses façons différentes d'atteindre le même objectif et dans lesquelles vous avez également la liberté de lancer la vôtre.

Les libertés de typage lâche et sans schéma de NoSQL doivent être adoptées et vous ne devriez pas vous inquiéter d'essayer de suivre une structure rigide et prédéfinie que vous connaissez peut-être lors de l'utilisation d'un SGBDR.

En conclusion, il n'y a pas vraiment de bonne voie pour stocker des données dans Redis, par ex. Le client C # Redis fait certaines hypothèses afin de fournir une API de haut niveau autour des POCO et il blob les POCO dans les valeurs de chaîne binaire sécurisées de Redis - bien que d'autres clients préfèrent stocker les propriétés d'une entité dans Redis Hachages (Dictionnaires) à la place . Les deux fonctionneront.