sql >> Database teknologi >  >> NoSQL >> Redis

ServiceStack.Net Redis:Lagring af relaterede objekter vs. relaterede objekt-id'er

I stedet for at gen-hash en masse anden dokumentation, der er derude i naturen, vil jeg liste et par rundt for lidt baggrundsinformation omkring Redis + ServiceStack's Redis Client:

  • Hvad skal du tænke på, når du designer en NoSQL Redis-applikation
  • Design af en NoSQL-database ved hjælp af Redis
  • Generel oversigt over Redis og .NET
  • Skemaløs versionering og datamigrering med C# Redis Client

Der er ingen magi - Redis er et tomt lærred

Først vil jeg påpege, at brug af Redis som et datalager blot giver et tomt lærred og ikke har noget begreb om relaterede enheder i sig selv. dvs. det giver bare adgang til distribuerede comp-sci datastrukturer. Hvordan relationer bliver lagret er i sidste ende op til klientdriveren (dvs. ServiceStack C# Redis Client) eller appudvikleren ved at bruge Redis' primitive datastrukturoperationer. Da alle de store datastrukturer er implementeret i Redis, har du som udgangspunkt fuld frihed til, hvordan du vil strukturere og opbevare dine data.

Tænk, hvordan du ville strukturere relationer i kode

Så den bedste måde at tænke på, hvordan man gemmer ting i Redis, er fuldstændigt at se bort fra, hvordan data er lagret i en RDBMS-tabel og tænke på, hvordan det er gemt i din kode, dvs. ved at bruge de indbyggede C#-samlingsklasser i hukommelsen - som Redis afspejler i adfærd med deres server-side data-strukturer.

På trods af ikke at have et koncept med relaterede enheder, Redis' indbyggede Set og Sorteret Sæt datastrukturer giver den ideelle måde at gemme indeks på. For eksempel. Redis's Set samling gemmer kun maks. 1 forekomst af et element. Det betyder, at du trygt kan tilføje elementer/nøgler/id'er til den og være ligeglad med, om varen allerede eksisterer, da slutresultatet vil være det samme, hvis du havde kaldt det 1 eller 100 gange - dvs. det er idempotent, og i sidste ende er der kun 1 element gemt i sættet. Så en almindelig brugssag er, når du gemmer en objektgraf (aggregeret rod), at gemme de underordnede enheds-id'er (aka fremmednøgler) i et sæt, hver gang du gemmer modellen.

Visualisering af dine data

For en god visualisering af, hvordan entiteter er gemt i Redis, anbefaler jeg at installere Redis Admin UI, som fungerer godt med ServiceStack's C# Redis Client, da den bruger nøglenavnekonventionen nedenfor til at give en flot hierarkisk visning, der grupperer dine indtastede entiteter sammen (på trods af alle nøgler). eksisterende i det samme globale nøglerum).

For at se og redigere en enhed skal du klikke på Rediger link for at se og ændre den valgte enheds interne JSON-repræsentation. Forhåbentlig vil du være i stand til at træffe bedre beslutninger om, hvordan du designer dine modeller, når du kan se, hvordan de opbevares.

Hvordan POCO/enheder gemmes

C# Redis-klienten fungerer med alle POCO'er, der har en enkelt primær nøgle - som som standard forventes at være Id (selvom denne konvention kan tilsidesættes med ModelConfig). Grundlæggende bliver POCO'er gemt i Redis som serialiseret JSON med både typeof(Poco).Name og Id bruges til at danne en unik nøgle for den instans. F.eks.:

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

POCO'er i C#-klienten serialiseres traditionelt ved hjælp af ServiceStacks hurtige Json Serializer, hvor kun egenskaber med offentlige gettere serialiseres (og offentlige sættere for at blive de-serialiseret tilbage).

Standarder kan tilsidesættes med [DataMember] attrs, men anbefales ikke, da det hæmmer dine POCO'er.

Enheder er blobbed

Så ved at vide, at POCO'er i Redis bare er udslettet, ønsker du kun at beholde ikke-aggregerede roddata på dine POCO'er som offentlige ejendomme (medmindre du med vilje ønsker at gemme overflødige data). En god konvention er at bruge metoder til at hente de relaterede data (da de ikke bliver serialiseret), men fortæller også din app, hvilke metoder der foretager fjernopkald for at læse data.

Så spørgsmålet om, hvorvidt Feed skal gemmes hos Brugeren er, hvorvidt det er ikke-aggregerede roddata, dvs. om du vil have adgang til brugernes feeds uden for brugerens kontekst? Hvis nej, så forlad List<Feed> Feeds egenskab på User type.

Vedligeholdelse af tilpassede indekser

Hvis du dog gerne vil holde alle feeds tilgængelige uafhængigt, dvs. med redisFeeds.GetById(1) så vil du gerne gemme det uden for brugeren og vedligeholde et indeks, der forbinder de 2 entiteter.

Som du har bemærket, er der mange måder at gemme relationer mellem enheder på, og hvordan du gør det er i høj grad et spørgsmål om præference. For den underordnede enhed i et forælder>barn forhold, du altid ønsker at gemme PrentId med den underordnede enhed. For forælderen kan du enten vælge at gemme en samling af ChildIds med modellen, og lav derefter en enkelt hentning for alle underordnede enheder for at rehydrere modellen.

En anden måde er at vedligeholde indekset uden for den overordnede dto i sit eget Set for hver forældreinstans. Nogle gode eksempler på dette er i C#-kildekoden til Redis StackOverflow-demoen, hvor forholdet mellem Users > Questions og Users > Answers er gemt i:

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

Selvom C# RedisClient inkluderer understøttelse af en standard Parent/Child-konvention via dens TParent.StoreRelatedEntities(), TParent.GetRelatedEntities<TChild>() og TParent.DeleteRelatedEntities() API'er, hvor et indeks vedligeholdes bag scenen, der ser ud som:

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

Dette er faktisk blot nogle af dine mulige muligheder, hvor der er mange forskellige måder at opnå det samme mål på, og hvor du også har friheden til at rulle dine egne.

NoSQL's skemaløse friskrivningsfriheder bør omfavnes, og du bør ikke være bekymret for at prøve at følge en stiv, foruddefineret struktur, som du måske kender, når du bruger et RDBMS.

Som konklusion er der ingen rigtig rigtig måde at gemme data i Redis, f.eks. C# Redis-klienten gør nogle antagelser for at give en API på højt niveau omkring POCO'er, og den blokerer POCO'erne i Redis' binært sikre strengværdier - selvom der er andre klienter, der vil foretrække at gemme en enhedsegenskaber i Redis Hashes (ordbøger) i stedet for . Begge vil virke.




  1. MongoDB tilføjer til samlingsfelt fra basis 1

  2. 3 måder at returnere en tilfældig prøve af dokumenter fra en MongoDB-samling

  3. Mongoose returnerer udefineret for et eksisterende felt

  4. Sådan genopretter du forbindelse til Redis-klient efter genstart/skalering af Redis-serveren