redis是文档型的,nosql中难处理的是关系。

比如人可以发博客,博客可以有分类。按照传统sql中,用户表和分类表都是主表,博客表是从表,有用户的外键和分类的外键

如果使用文档型的思考方式。

为用户A(User id=1)存储他的博客,在redis中是list或set

为分类A(Cate id=1)存储分类下的博客,在redis中是list或set

则当用户A向分类A中添加一条新博客时,需要同时向两个list(或set)中增加数据,而且理论上应该是事务的,修改的时候也需要同时修改两个。

这样的好处是读操作是完全优化的,直接从一个key中读出来的东西,马上就可以用

坏处是写操作太复杂,稍不注意可能就漏掉什么东西,更新博客需要更新非常多个list中的元素。

 

ServiceStack的redis客户端专门为这种情况提供了几个方法。

先来看实体类

public class User
{
public int Id { get; set; } public string Name { get; set; } } public class Blog
{
public int Id { get; set; } public string Title { get; set; }
} public class Cate
{
public int Id { get; set; } public string Name { get; set; }
}

很简单的3个类,用于表示用户,分类,博客3种概念

使用强类型的client保存3个实例

var clientsManager = new PooledRedisClientManager();
using (IRedisClient redis = clientsManager.GetClient())
{
redis.FlushAll(); var u = new User { Id = 1, Name = "A" }; var c = new Cate { Id = 1, Name = "A" }; var blog = new Blog { Id = 1, Title = "blog" }; redis.As<User>().Store(u);
redis.As<Cate>().Store(c);
redis.As<Blog>().Store(blog); }

可以通过客户端软件查看,3个实体都保存成功,但是并没有体现关系

redis.As<User>().StoreRelatedEntities(u.Id, blog);
redis.As<Cate>().StoreRelatedEntities(c.Id, blog);

之后调用保存关系的语句,as的是主表,第一个是主表主键,第二个是从对象

redis中,新建了2个key,ref:Cate/Blog:1和ref:User/Blog:1

他们的值是一个set

set中的具体内容并不是对象本身,而是对象在urn中的key

 

 

var blogs = redis.As<User>().GetRelatedEntities<Blog>(u.Id);

可以通过相关语句来获取从表内容

直接取到了blog的实体

 

但是在删除的时候有一个bug

他的方法指定的第二个参数是childId,所以我们传进去id,但是删除不掉

 

redis.As<User>().DeleteRelatedEntity<Blog>(u.Id, blog);

不使用id,而使用对象,也依然删除不掉

查看源码发现,当他运行从set中删除东西的时候,找key是对的,但是要被删掉的元素生成的不对

添加的时候,他拿UrnKey<T>(x)生成了实体保存的key,而删除的时候没有

删除的时候,直接是序列化的,则1,序列化后就是1,而我们的set中,并没有1这个值,所以是没有删掉任何东西的。

client的UrnKey是个internal的方法,再次被恶心了

redis.As<User>().DeleteRelatedEntity<Blog>(u.Id, (redis as RedisNativeClient).NamespacePrefix + IdUtils.CreateUrn(blog));

我们只能使用这么复杂的方式,等于把他内部的代码都拿到外面来处理了,当然你可以clone他的源码去改或者写扩展方法。

 

 

根据关系的key,我们大概可以分析出

ref:主表/从表:主表主键值

但这样的方式有一定的局限性,就是对同一个主从类型,他们之间只能表达一种关系。

比如人与博客,如果我需要表达 人写的博客,人推荐的博客 这两种关系(都是人与博客的),则无法实现

比如User 1,他写了Blog 1,推荐了Blog 2。但是他们都会被加入到ref:User/Blog:1中,无法区分是他写的还是他推荐的。

所以我们需要为两种类型之间的关系去给一个名字,来区分到底是那种关系

 

在RedisTypedClient<T>中有一个GetChildReferenceSetKey方法,是来生成这个key的,private方法,再次被恶心

当然,可以通过对NamespacePrefix设置一个不同的值来区分,但是感觉上怪怪的,因为这个在我看来是不同的应用程序,为防止key重复而设置的

有兴趣的朋友可以写几个扩展方法,反正源码基本都能看到

 

再再再次被恶心到的是,竟然github没有开放issues提交

ServiceStack.Redis 中关系操作的局限与bug的更多相关文章

  1. Service-stack.redis 使用PooledRedisClientManager 速度慢的原因之一

    现在越来越多的开发者使用service-stack.redis 来进行redis的访问,但是获取redisclient的方式有多种方式,其中有一种从缓冲池获取client的方式很是得到大家的认可. L ...

  2. Redis中的事务及乐观锁的实现

    介绍 Redis中的事务(transaction)是一组命令的集合.     事务同命令一样都是Redis最小的执行单位,一个事务中的命令要么都执行,要么都不执行.     Redis事务的实现需要用 ...

  3. 用C#封装的ServiceStack.redis操作类

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  4. serviceStack.Redis 在PooledRedisClientManager 中设置密码

    ServiceStack.Redis 是一个C#访问Redis的客户端,可以说可以通过它实现所有需要Redis-Cli的功能.但是今天我在主Redis 实例设置了访问密码,而在slave 上没有设置, ...

  5. redis的hash操作在集中式session中的应用

    在集群部署时,为了高可用性的目的,往往把session进行共享,共享分为两种:session复制和集中式管理. redis在session集中式管理中可以起到比较大的作用. 制约session集中式共 ...

  6. C#中使用ServiceStack.Redis

    .Net操作Redis数据类型String public class DoRedisString : DoRedisBase { #region 赋值 /// <summary> /// ...

  7. 新姿势!Redis中调用Lua脚本以实现原子性操作

    背景:有一服务提供者Leader,有多个消息订阅者Workers.Leader是一个排队程序,维护了一个用户队列,当某个资源空闲下来并被分配至队列中的用户时,Leader会向订阅者推送消息(消息带有唯 ...

  8. redis的字符串操作以及在django中的使用

    redis ----redis.MongoDB : 非关系型数据库 redis   存储在内存中 MongoDB 存储在硬盘中 l  简介 redis是一个key-value存储系统 , 支持持久化 ...

  9. Redis中的持久化操作

       本篇博客主要来解说一下怎样Redis中的持久化操作,当然了不是一篇理论性的博客,主要还是分享一下在redis中怎样来配置持久化操作.  1.介绍  redis为了内部数据的安全考虑,会把本身的数 ...

随机推荐

  1. C#:实现快捷键自定义设置

    代码下载 C#实现快捷键自定义设置 需求 项目开发过程中,需要实现类似有道词典的软件设置中的自定义快捷键功能,如下图所示: 当我们相继按下Ctrl+Alt+M的时候,软件就会自动将快捷键显示在文本框中 ...

  2. ClamAV安装使用及API例子

    ClamAV是一款由Sourcefire组织开发的开源杀毒引擎,Sourcefire同时也是Snort入侵检测引擎的所有者.ClamAV提供了一种更为快速灵活的框架用以检测恶意代码和软件产品.可以作为 ...

  3. VB中WinSock控件的属性、方法、事件及应用

    一.WinSock简介       Socket(套接字)最初是由加利福尼亚大学Berkeley(伯克利)分校为UNIX操作系统开发的网络通信接口,随着UNIX的广泛使用,Socket成为当前最流行的 ...

  4. git .gitignore 文件 解决二进制文件冲突问题

    .gitignore  主要是添加 忽略文件 .最近团队开发经常出现 UserInterfaceState.xcuserstate 冲突,打开发现是二进制文件 ,没法解决冲突. 只好 rm -rf 之 ...

  5. 解决Visual Studio 调试时候不能直接访问.json后缀文件的问题

    Web.config中作如下配置: <system.webServer> <staticContent> <mimeMap fileExtension=".js ...

  6. RS开发中的一些小技巧[不定期更新]

    从9月份一直忙到了现在,项目整体的改版工作也完成了十有八九了,有些事情只有你自己真正的做了,你才能明白:哦,原来还可以这个样子,这样做真的好了很多呢,接下来我就分享一些最近遇到的RS开发的一些小技巧, ...

  7. js笔记--1

    1.创建一个layer层 var GameLayer = cc.Layer.extend({ _time:null, _ship:null, _backSky:null, // 构造函数 ctor:f ...

  8. ASP.NET MVC 分部视图

    @model PartViewDemo.Models.HomeInfo@using PartViewDemo.Models;@{ ViewBag.Title = "Index";} ...

  9. Navi.Soft30.开放平台.百度.开发手册

    1系统简介 1.1功能简述 现在是一个信息时代,并且正在高速发展.以前获取信息的途径非常少,可能只有电视台,收音机等有限的来源,而现在的途径数不胜数,如:QQ,微信,官方网站,个人网站等等 本开发手册 ...

  10. memcached命令

    memcached相对于redis来说,简直简单太多,命令也少很多,一般应用都是使用redis,但了解一下也还是不错的. 具体命令和用法很参见:http://www.runoob.com/memcac ...