Redis
 sql >> Base de Dados >  >> NoSQL >> Redis

ServiceStack.Net Redis:armazenando objetos relacionados vs. IDs de objetos relacionados


Em vez de refazer muitas outras documentações que estão por aí, listarei algumas para obter algumas informações básicas sobre o Redis + ServiceStack's Redis Client:
  • O que pensar ao projetar um aplicativo NoSQL Redis
  • Projetando um banco de dados NoSQL usando Redis
  • Visão geral do Redis e .NET
  • Versão sem esquema e migração de dados com C# Redis Client

Não existe mágica - Redis é uma tela em branco


Primeiro, quero salientar que usar o Redis como um armazenamento de dados fornece apenas uma tela em branco e não possui nenhum conceito de entidades relacionadas por si só. ou seja, ele apenas fornece acesso a estruturas de dados comp-sci distribuídas. Como os relacionamentos são armazenados depende, em última análise, do driver do cliente (ou seja, ServiceStack C# Redis Client) ou do desenvolvedor do aplicativo, usando as operações de estrutura de dados primitivas do Redis. Como todas as principais estruturas de dados são implementadas no Redis, você basicamente tem total liberdade sobre como deseja estruturar e armazenar seus dados.

Pense em como você estruturaria relacionamentos no código


Portanto, a melhor maneira de pensar em como armazenar coisas no Redis é desconsiderar completamente como os dados são armazenados em uma tabela RDBMS e pensar em como eles são armazenados em seu código, ou seja, usando as classes de coleção C# integradas na memória - que o Redis espelha no comportamento com suas estruturas de dados do lado do servidor.

Apesar de não ter um conceito de entidades relacionadas, o Set integrado do Redis e SortedSet estruturas de dados fornecem a maneira ideal de armazenar índices. Por exemplo. Conjunto do Redis A coleção armazena apenas no máximo 1 ocorrência de um elemento. Isso significa que você pode adicionar itens/chaves/ids com segurança a ele e não se importar se o item já existe, pois o resultado final será o mesmo se você o tivesse chamado 1 ou 100 vezes - ou seja, é idempotente e, finalmente, apenas 1 elemento permanece armazenado em o conjunto. Portanto, um caso de uso comum é quando armazenar um gráfico de objeto (raiz agregada) é armazenar os IDs de entidade filho (também conhecido como chaves estrangeiras) em um conjunto toda vez que você salvar o modelo.

Visualizando seus dados


Para uma boa visualização de como as Entidades são armazenadas no Redis, recomendo instalar a interface do usuário do Redis Admin, que funciona bem com o C# Redis Client do ServiceStack, pois usa a convenção de nomenclatura de chave abaixo para fornecer uma boa visão hierárquica, agrupando suas entidades digitadas (apesar de todas as chaves existente no mesmo keyspace global).

Para visualizar e editar uma Entidade, clique no botão Editar link para ver e modificar a representação JSON interna da entidade selecionada. Espero que você possa tomar melhores decisões sobre como projetar seus modelos quando puder ver como eles são armazenados.

Como POCO/Entidades são armazenadas


O C# Redis Client funciona com quaisquer POCOs que tenham uma única chave primária - que por padrão deve ser Id (embora essa convenção possa ser substituída por ModelConfig). Essencialmente, os POCOs são armazenados no Redis como JSON serializado com o typeof(Poco).Name e o Id usado para formar uma chave exclusiva para essa instância. Por exemplo:
urn:Poco:{Id} => '{"Id":1,"Foo":"Bar"}'

Os POCOs no cliente C# são serializados convencionalmente usando o serializador Json rápido do ServiceStack, onde apenas as propriedades com getters públicos são serializadas (e setters públicos para serem desserializados de volta).

Os padrões são substituíveis com [DataMember] attrs, mas não é recomendado, pois enferruja seus POCOs.

Entidades são blobbadas


Portanto, sabendo que os POCOs no Redis são apenas blobbados, você só deseja manter dados raiz não agregados em seus POCOs como propriedades públicas (a menos que você queira armazenar dados redundantes propositalmente). Uma boa convenção é usar métodos para buscar os dados relacionados (já que eles não serão serializados), mas também informar ao seu aplicativo quais métodos fazem chamadas remotas para ler dados.

Portanto, a questão de saber se o Feed deve ser armazenado com o Usuário é se são ou não dados raiz não agregados, ou seja, se você deseja ou não acessar os feeds dos usuários fora do contexto do usuário? Se não, deixe a List<Feed> Feeds propriedade no User tipo.

Manter índices personalizados


Se, no entanto, você quiser manter todos os feeds acessíveis de forma independente, ou seja, com redisFeeds.GetById(1) então você vai querer armazená-lo fora do usuário e manter um índice ligando as 2 entidades.

Como você notou, há muitas maneiras de armazenar relacionamentos entre entidades e como você faz isso é, em grande parte, uma questão de preferência. Para a entidade filha em um pai>filho relacionamento você sempre deseja armazenar o ParentId com a entidade filha. Para o Pai, você pode optar por armazenar uma coleção de ChildIds com o modelo e, em seguida, faça uma busca única para todas as entidades filhas para reidratar o modelo.

Outra maneira é manter o índice fora do dto pai em seu próprio Set para cada instância pai. Alguns bons exemplos disso estão no código-fonte C# da demonstração do Redis StackOverflow, onde o relacionamento de Users > Questions e Users > Answers é armazenado em:
idx:user>q:{UserId} => [{QuestionId1},{QuestionId2},etc]
idx:user>a:{UserId} => [{AnswerId1},{AnswerId2},etc]

Embora o C# RedisClient inclua suporte para uma convenção Pai/Filho padrão por meio de TParent.StoreRelatedEntities(), TParent.GetRelatedEntities<TChild>() e TParent.DeleteRelatedEntities() APIs em que um índice é mantido nos bastidores que se parece com:
ref:Question/Answer:{QuestionId} => [{answerIds},..]

Efetivamente, essas são apenas algumas de suas opções possíveis, onde existem muitas maneiras diferentes de alcançar o mesmo fim e nas quais você também tem a liberdade de rolar o seu próprio.

As liberdades de digitação solta e sem esquema do NoSQL devem ser adotadas e você não deve se preocupar em tentar seguir uma estrutura rígida e predefinida com a qual você pode estar familiarizado ao usar um RDBMS.

Concluindo, não existe um caminho certo real para armazenar dados no Redis, por exemplo O C# Redis Client faz algumas suposições para fornecer uma API de alto nível em torno de POCOs e blobs os POCOs nos valores de string seguros para binários do Redis - embora existam outros clientes que prefiram armazenar propriedades de entidades em Redis Hashes (dicionários) em vez disso . Ambos funcionarão.