Zac*_*eth 39 .net c# redis servicestack
我的团队决定通过ServiceStack.net Redis Client与Redis合作,作为我们正在开发的新的高容量网站的底层存储库.我不确定在哪里查找这个问题的文档(对于一般的Redis文档或特定的ServiceStack.Net文档或两者) - 实际上是否有关于如何通过ServiceStack.Net实现Redis的文档的权威来源,包括您需要了解Redis概念和ServiceStack.Net概念,还是需要分别整合两个方面的文档才能全面了解?
我正在努力解决如何在模型的对象图中存储相关对象.这是一个我想要使用的简单场景:
系统中有两个对象:User和Feed.在RDBMS术语中,这两个对象具有一对多关系,即a User具有Feed对象集合,而feed只能属于一个User.Redis将始终通过用户访问Feed,但有时我们会希望通过Feed实例访问用户.
所以我的问题是我们是应该将相关对象存储为属性还是应该存储Id相关对象的值?为了显示:
方法A:
public class User
{
public User()
{
Feeds = new List<Feed>();
}
public int Id { get; set; }
public List<Feed> Feeds { get; set; }
// Other properties
}
public class Feed
{
public long Id { get; set; }
public User User { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
方法B:
public class User
{
public User()
{
FeedIds = new List<long>();
}
public long Id { get; set; }
public List<long> FeedIds { get; set; }
public List<Feed> GetFeeds()
{
return repository.GetFeeds( FeedIds );
}
}
public class Feed
{
public long Id { get; set; }
public long UserId { get; set; }
public User GetUser()
{
return repository.GetUser( UserId );
}
}
Run Code Online (Sandbox Code Playgroud)
以上哪种方法效果最好?我已经看到了各种示例中使用的两种方法,但我得到的印象是,我看到的一些示例可能不是最佳实践.
一些简单的相关问题:
IList<Feed>而不是List<Feed>?很抱歉,如果这些问题有点基础 - 直到2周前我甚至都没有听说过Redis - 更不用说ServiceStack了 - (我的团队中也没有人)所以我们真的从头开始......
myt*_*thz 66
我会列出一些关于Redis + ServiceStack的Redis客户端的一些背景信息,而不是重新散列很多其他文档.
首先,我想指出,使用Redis作为数据存储只提供一个空白画布,并且本身没有任何相关实体的概念.即它只提供对分布式comp-sci数据结构的访问.如何存储关系最终取决于客户端驱动程序(即ServiceStack C#Redis客户端)或应用程序开发人员,使用Redis的原始数据结构操作.由于所有主要数据结构都是在Redis中实现的,因此您基本上可以完全自由地构建和存储数据.
因此,考虑如何在Redis中存储内容的最佳方法是完全忽略数据如何存储在RDBMS表中,并考虑它如何存储在代码中,即在内存中使用内置的C#集合类 - Redis使用服务器端数据结构反映行为.
尽管没有相关实体的概念,但Redis的内置Set和SortedSet数据结构提供了存储索引的理想方法.例如,Redis的Set集合仅存储一个元素的最多1次.这意味着您可以安全地向其添加项目/键/ ID,而不关心项目是否已经存在,因为如果您将其称为1或100次,最终结果将是相同的 - 即它是幂等的,并且最终只有1个元素仍然存储在集.因此,一个常见的用例是,每次保存模型时,存储对象图(聚合根)都是将子实体ID(也称为外键)存储到Set中.
为了更好地可视化实体在Redis中的存储方式,我建议安装Redis Admin UI,它与ServiceStack的C#Redis客户端配合使用,因为它使用下面的密钥命名约定来提供一个很好的分层视图,将您键入的实体分组在一起(尽管所有密钥都是如此)存在于同一个全局密钥空间中).
要查看和编辑实体,请单击" 编辑"链接以查看和修改所选实体的内部JSON表示.希望一旦您能够看到它们的存储方式,您就能够更好地决定如何设计模型.
在C#Redis的客户与具有一个主键的任何波苏斯工作-在默认情况下预计Id(虽然这个约定重写与ModelConfig).基本上,POCO作为序列化的JSON存储到Redis中,typeof(Poco).Name并且Id用于形成该实例的唯一键.例如:
urn:Poco:{Id} => '{"Id":1,"Foo":"Bar"}'
Run Code Online (Sandbox Code Playgroud)
C#Client中的POCO通常使用ServiceStack的快速Json Serializer进行序列化,其中只有具有公共getter的属性被序列化(并且公共setter被反序列化).
默认值可以使用[DataMember]attrs 覆盖但不建议使用,因为它会使您的POCO更新.
因此,要知道Redis中的POCO只是blobbed,您只想将POCO上的非聚合根数据保留为公共属性(除非您有意存储冗余数据).一个很好的约定是使用方法来获取相关数据(因为它不会被序列化),但也告诉你的应用程序哪些方法进行远程调用来读取数据.
因此,关于Feed是否应该与用户一起存储的问题是它是否是非聚合根数据,即您是否想要访问用户上下文之外的用户提要?如果不是,则将List<Feed> Feeds属性保留在User类型上.
但是,如果您希望保持所有Feed可以独立访问,redisFeeds.GetById(1)那么您将希望将其存储在用户之外并维护链接2个实体的索引.
正如您已经注意到,存储实体之间关系的方法有很多,您如何这样做主要取决于偏好.对于父>子关系中的子实体,您总是希望将ParentId与子实体一起存储.对于Parent,您可以选择将ChildIds集合与模型一起存储,然后对所有子实体执行单次提取以重新保持模型.
另一种方法是将父dto之外的索引维护在每个父实例的自己的Set中.这样的一些很好的例子是在C#源代码中的Redis的StackOverflow上演示其中的关系Users > Questions,并Users > Answers存储在:
idx:user>q:{UserId} => [{QuestionId1},{QuestionId2},etc]
idx:user>a:{UserId} => [{AnswerId1},{AnswerId2},etc]
Run Code Online (Sandbox Code Playgroud)
虽然C#RedisClient确实通过其TParent.StoreRelatedEntities()支持默认的父/子约定,TParent.GetRelatedEntities<TChild>()并且TParent.DeleteRelatedEntities()API支持在场景后面维护索引,如下所示:
ref:Question/Answer:{QuestionId} => [{answerIds},..]
Run Code Online (Sandbox Code Playgroud)
实际上,这些只是您可能的一些选择,其中有许多不同的方法可以实现相同的目标,并且您也可以自由选择.
应该接受NoSQL的无模式,松散类型的自由,并且您不应该担心尝试遵循使用RDBMS时可能熟悉的严格的预定义结构.
总而言之,没有真正正确的方法在Redis中存储数据,例如,C#Redis客户端做了一些假设,以便在POCO周围提供高级API,并在Redis的二进制安全字符串值中填充POCO - 尽管还有其他客户更愿意在Redis Hashes(Dictionaries)中存储实体属性.两者都有效.
| 归档时间: |
|
| 查看次数: |
15594 次 |
| 最近记录: |