与其重新散布大量的其他文档,我不如列出一些有关Redis + ServiceStack的Redis Client的背景信息:
- 设计NoSQL Redis应用程序时的注意事项
- 使用Redis设计NoSQL数据库
- Redis和.NET的概述
- 使用C#Redis Client进行无模式版本控制和数据迁移
没有魔法-Redis是一块空白画布
首先,我想指出的是,将Redis用作数据存储仅提供了一个空白画布,并且本身没有任何相关实体的概念。即,它仅提供对分布式comp-
sci数据结构的访问。通过使用Redis的原始数据结构操作,如何存储关系最终取决于客户端驱动程序(即ServiceStack C#Redis
Client)或应用程序开发人员。由于所有主要数据结构都是在Redis中实现的,因此您基本上可以完全自由地构造和存储数据。
想想如何在代码中构建关系
因此,考虑如何在Redis中存储内容的最好方法是完全不考虑数据在RDBMS表中的存储方式,而考虑数据在代码中的存储方式,即在内存中使用内置的C#集合类-
Redis通过其服务器端数据结构来反映行为。
尽管没有相关实体的概念,Redis的内置 Set 和 SortedSet 数据结构还是存储索引的理想方法。例如,Redis的 Set
集合最多只能存储1个元素。这意味着您可以安全地向其中添加项目/键/标识,而不必关心该项目是否已经存在,因为如果您将其调用1或100次,最终结果将是相同的-
即它是幂等的,最终仅将1个元素保留在其中集合。因此,在存储对象图(聚合根)时,一个常见的用例是每次保存模型时将子实体ID(又称为外键)存储到Set中。
可视化您的数据
为了更好地可视化实体在Redis中的存储方式,我建议安装与ServiceStack的C#Redis Client配合使用的Redis Admin
UI,因为它使用下面的键命名约定提供了一个很好的层次结构视图,将键入的实体分组在一起(尽管所有键)存在于同一全局键空间中)。
要查看和编辑实体,请单击“ 编辑”
链接以查看和修改所选实体的内部JSON表示形式。希望一旦看到模型的存储方式,您将能够对如何设计模型做出更好的决策。
POCO /实体的存储方式
C#Redis客户端可与具有单个主键的任何POCO一起使用-
默认情况下应为主键
Id(尽管此约定可通过ModelConfig覆盖)。本质上,POCO作为序列化JSON存储在Redis中,同时使用
typeof(Poco).Name和
Id来为该实例形成唯一密钥。例如:
urn:Poco:{Id} => '{"Id":1,"Foo":"Bar"}'C#客户端中的POCO通常使用ServiceStack的快速Json序列化器进行序列化,在序列化器中,仅对具有公共获取器的属性进行序列化(并通过公共获取器反序列化)。
默认值可以用[DataMember]
attrs 覆盖,但不建议使用,因为它会使您的POCO变得丑陋。
实体被爆
因此,知道Redis中的POCO只是泛滥了,您只想将非聚合的根数据保留在POCO上作为公共属性(除非您有意存储冗余数据)。一个好的约定是使用方法来获取相关数据(因为它不会被序列化),但还告诉您的应用哪些方法进行了远程调用以读取数据。
因此,关于 Feed 是否应与 用户
一起存储的问题是,它是否是非聚合的根数据,即您是否要在用户上下文之外访问用户feed?如果否,则将
List<Feed>Feeds属性保留在
User类型上。
维护自定义索引
但是,如果您想保持所有提要独立访问,即使用,
redisFeeds.GetById(1)则需要将其存储在用户外部并维护一个链接这两个实体的索引。
正如您已经注意到的,有很多方法可以存储实体之间的关系,并且如何存储很大程度上取决于偏好。对于 parent >
child关系中的子实体,您总是希望将 ParentId 与该子实体一起存储。对于父级,您可以选择与模型一起存储 ChildId
的集合,然后对所有子实体进行一次提取以重新 补充 模型。
另一种方法是为每个父实例在其自己的 Set
中的父dto外部维护索引。这样的一些很好的例子是在C#源代码中的Redis的StackOverflow上演示其中的关系`Users
Questions
,并Users > Answers`存储在:
idx:user>q:{UserId} => [{QuestionId1},{QuestionId2},etc]idx:user>a:{UserId} => [{AnswerId1},{AnswerId2},etc]虽然C#RedisClient不包括通过其默认的父/子惯例支持TParent.StoreRelatedEntities()
,
TParent.GetRelatedEntities<TChild>()以及
TParent.DeleteRelatedEntities()API的其中一个指标保持在幕后,看起来像:
ref:Question/Answer:{QuestionId} => [{answerIds},..]实际上,这些只是您可能的选择中的一些,在其中有许多种不同的方法可以达到相同的目的,并且您还可以自由滚动自己的目标。
应该拥抱NoSQL的无模式的,松散的自由,并且您不必担心遵循遵循在使用RDBMS时可能熟悉的刚性,预定义的结构。
总之,没有真正 正确的方法 在Redis中存储数据,例如,C#Redis
Client进行了一些假设,以提供围绕POCO的高级API,并且在Redis的二进制安全字符串值中使POCO斑点化-
尽管还有其他方法客户将更喜欢将实体属性存储在Redis哈希(字典)中。两者都会起作用。



