很久以前写了一篇文章 .NET中使用Redis 介绍了如何安装Redis服务端,以及如何在.NET中调用Redis读取数据。本文简单介绍如何设计NoSQL数据库,以及如何使用Redis来存储对象。

和传统的关系型数据库不同,NoSQL大部分都是以键值对存储在内存中的,我们不能直接把RDBMS里面的一些做法直接移植到NoSQL中来,一个最主要的原因是,在NoSQL中缺少RDBMS中的一些诸如join ,union以及一些在关系型数据库中效率很高的执行语句,这些在NoSQL不能很好的支持,或者说效率低。

下文首先通过例子介绍在SQLServer中设计一个DB系统以及与NoSQL环境中设计一个DB的区别,最后演示如何在Redis中对数据进行读写操作。

一个简单的博客系统

假设我们要设计一个简单的博客系统,用户可以注册一个博客(Blog),然后可以在上面写文章(Post),文章可以分类(Category)以及添加标签(Tag),用户可以对文章进行评论(Comment)。

在该系统中,我们需要实现,如下基本功能:

  • 首页:显示所有人的博客
  • 首页:显示最近的所有发表的文章
  • 首页:显示所有的最近的评论
  • 首页:显示博客的标签云
  • 首页:显示所有的分类
  • 文章页面:显示文章以及所有的评论
  • 文章页面:添加评论
  • 标签页面:显示所有标签以及标签对应的文章
  • 分类页面:显示所有分类以及分类对应的文章

如果在SQLServer中,相信很简单就可以设计出这样一个DB了。

在NoSQL环境中,我们不能直接将上面的结构搬进来,所以需要根据需求重新设计我们的模型。

定义实体

在NoSQL环境下,所有的数据其实都是以key和value的形式存储在内存中的,value通常是序列化为字符串保存的。我们使用redis客户端的时候,可以直接将对象存储,这些客户端在内部实现上帮助我们进行了序列化。所以第一步就是需要定义实体模型:

首先来看User实体:

 
 
 
 
 
 

C#

 
public class User
{
public User()
{
this.BlogIds = new List<long>();
}

public long Id { get; set; }
public string Name { get; set; }
public List<long> BlogIds { get; set; }
}

1
2
3
4
5
6
7
8
9
10
11
public class User
{
    public User()
    {
        this.BlogIds = new List<long>();
    }
 
    public long Id { get; set; }
    public string Name { get; set; }
    public List<long> BlogIds { get; set; }
}

User实体中,包含了用户的Id,Name以及博客的Id。

然后Blog实体:

 
 
 
 
 
 

C#

 
public class Blog
{
public Blog()
{
this.Tags = new List<string>();
this.BlogPostIds = new List<long>();
}

public long Id { get; set; }
public long UserId { get; set; }
public string UserName { get; set; }
public List<string> Tags { get; set; }
public List<long> BlogPostIds { get; set; }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Blog
{
    public Blog()
    {
        this.Tags = new List<string>();
        this.BlogPostIds = new List<long>();
    }
 
    public long Id { get; set; }
    public long UserId { get; set; }
    public string UserName { get; set; }
    public List<string> Tags { get; set; }
    public List<long> BlogPostIds { get; set; }
}

包含了标签Tag,以及文章Id列表。

文章BolgPost实体:

 
 
 
 
 
 

C#

 
public class BlogPost
{
public BlogPost()
{
this.Categories = new List<string>();
this.Tags = new List<string>();
this.Comments = new List<BlogPostComment>();
}

public long Id { get; set; }
public long BlogId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public List<string> Categories { get; set; }
public List<string> Tags { get; set; }
public List<BlogPostComment> Comments { get; set; }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class BlogPost
{
    public BlogPost()
    {
        this.Categories = new List<string>();
        this.Tags = new List<string>();
        this.Comments = new List<BlogPostComment>();
    }
 
    public long Id { get; set; }
    public long BlogId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public List<string> Categories { get; set; }
    public List<string> Tags { get; set; }
    public List<BlogPostComment> Comments { get; set; }
}

包含了一篇文章的基本信息,如文章分类,文章标签,文章的评论。

最后看评论BlogPostComment实体:

 
 
 
 
 
 

C#

 
public class BlogPostComment
{
public string Content { get; set; }
public DateTime CreatedDate { get; set; }
}
1
2
3
4
5
public class BlogPostComment
{
    public string Content { get; set; }
    public DateTime CreatedDate { get; set; }
}

具体实现

实体定义好了之后,我们就可以开始具体实现了。为了演示,这里通过单元测试的方式实现具体功能:

首先要把Redis的服务端启动起来,然后在工程中新建一个Redis客户端,之后的所有操作都通过这个客户端进行。

 
 
 
 
 
 

C#

 
[TestFixture, Explicit, Category("Integration")]
public class BlogPostExample
{
readonly RedisClient redis = new RedisClient("localhost");

[SetUp]
public void OnBeforeEachTest()
{
redis.FlushAll();
InsertTestData();
}
}

1
2
3
4
5
6
7
8
9
10
11
12
[TestFixture, Explicit, Category("Integration")]
public class BlogPostExample
{
    readonly RedisClient redis = new RedisClient("localhost");
 
    [SetUp]
    public void OnBeforeEachTest()
    {
        redis.FlushAll();
        InsertTestData();
    }
}

在单元测试的SetUp中,我们插入一些模拟数据,插入数据的方法为InsetTestData方法:

 
 
 
 
 
 

C#

使用 CTRL+C 复制,使用 CTRL+V 粘贴。
public void InsertTestData()
{
var redisUsers = redis.As<User>();
var redisBlogs = redis.As<Blog>();
var redisBlogPosts = redis.As<BlogPost>();

var yangUser = new User { Id = redisUsers.GetNextSequence(), Name = "Eric Yang" };
var zhangUser = new User { Id = redisUsers.GetNextSequence(), Name = "Fish Zhang" };

var yangBlog = new Blog
{
Id = redisBlogs.GetNextSequence(),
UserId = yangUser.Id,
UserName = yangUser.Name,
Tags = new List<string> { "Architecture", ".NET", "Databases" },
};

var zhangBlog = new Blog
{
Id = redisBlogs.GetNextSequence(),
UserId = zhangUser.Id,
UserName = zhangUser.Name,
Tags = new List<string> { "Architecture", ".NET", "Databases" },
};

var blogPosts = new List<BlogPost>
{
new BlogPost
{
Id = redisBlogPosts.GetNextSequence(),
BlogId = yangBlog.Id,
Title = "Memcache",
Categories = new List<string> { "NoSQL", "DocumentDB" },
Tags = new List<string> {"Memcache", "NoSQL", "JSON", ".NET"} ,
Comments = new List<BlogPostComment>
{
new BlogPostComment { Content = "First Comment!", CreatedDate = DateTime.UtcNow,},
new BlogPostComment { Content = "Second Comment!", CreatedDate = DateTime.UtcNow,},
}
},
new BlogPost
{
Id = redisBlogPosts.GetNextSequence(),
BlogId = zhangBlog.Id,
Title = "Redis",
Categories = new List<string> { "NoSQL", "Cache" },
Tags = new List<string> {"Redis", "NoSQL", "Scalability", "Performance"},
Comments = new List<BlogPostComment>
{
new BlogPostComment { Content = "First Comment!", CreatedDate = DateTime.UtcNow,}
}
},
new BlogPost
{
Id = redisBlogPosts.GetNextSequence(),
BlogId = yangBlog.Id,
Title = "Cassandra",
Categories = new List<string> { "NoSQL", "Cluster" },
Tags = new List<string> {"Cassandra", "NoSQL", "Scalability", "Hashing"},
Comments = new List<BlogPostComment>
{
new BlogPostComment { Content = "First Comment!", CreatedDate = DateTime.UtcNow,}
}
},
new BlogPost
{
Id = redisBlogPosts.GetNextSequence(),
BlogId = zhangBlog.Id,
Title = "Couch Db",
Categories = new List<string> { "NoSQL", "DocumentDB" },
Tags = new List<string> {"CouchDb", "NoSQL", "JSON"},
Comments = new List<BlogPostComment>
{
new BlogPostComment {Content = "First Comment!", CreatedDate = DateTime.UtcNow,}
}
},
};

yangUser.BlogIds.Add(yangBlog.Id);
yangBlog.BlogPostIds.AddRange(blogPosts.Where(x => x.BlogId == yangBlog.Id).Map(x => x.Id));

zhangUser.BlogIds.Add(zhangBlog.Id);
zhangBlog.BlogPostIds.AddRange(blogPosts.Where(x => x.BlogId == zhangBlog.Id).Map(x => x.Id));

redisUsers.Store(yangUser);
redisUsers.Store(zhangUser);
redisBlogs.StoreAll(new[] { yangBlog, zhangBlog });
redisBlogPosts.StoreAll(blogPosts);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
public void InsertTestData()
{
    var redisUsers = redis.As<User>();
    var redisBlogs = redis.As<Blog>();
    var redisBlogPosts = redis.As<BlogPost>();
 
    var yangUser = new User { Id = redisUsers.GetNextSequence(), Name = "Eric Yang" };
    var zhangUser = new User { Id = redisUsers.GetNextSequence(), Name = "Fish Zhang" };
 
    var yangBlog = new Blog
    {
        Id = redisBlogs.GetNextSequence(),
        UserId = yangUser.Id,
        UserName = yangUser.Name,
        Tags = new List<string> { "Architecture", ".NET", "Databases" },
    };
 
    var zhangBlog = new Blog
    {
        Id = redisBlogs.GetNextSequence(),
        UserId = zhangUser.Id,
        UserName = zhangUser.Name,
        Tags = new List<string> { "Architecture", ".NET", "Databases" },
    };
 
    var blogPosts = new List<BlogPost>
    {
        new BlogPost
        {
            Id = redisBlogPosts.GetNextSequence(),
            BlogId = yangBlog.Id,
            Title = "Memcache",
            Categories = new List<string> { "NoSQL", "DocumentDB" },
            Tags = new List<string> {"Memcache", "NoSQL", "JSON", ".NET"} ,
            Comments = new List<BlogPostComment>
            {
                new BlogPostComment { Content = "First Comment!", CreatedDate = DateTime.UtcNow,},
                new BlogPostComment { Content = "Second Comment!", CreatedDate = DateTime.UtcNow,},
            }
        },
        new BlogPost
        {
            Id = redisBlogPosts.GetNextSequence(),
            BlogId = zhangBlog.Id,
            Title = "Redis",
            Categories = new List<string> { "NoSQL", "Cache" },
            Tags = new List<string> {"Redis", "NoSQL", "Scalability", "Performance"},
            Comments = new List<BlogPostComment>
            {
                new BlogPostComment { Content = "First Comment!", CreatedDate = DateTime.UtcNow,}
            }
        },
        new BlogPost
        {
            Id = redisBlogPosts.GetNextSequence(),
            BlogId = yangBlog.Id,
            Title = "Cassandra",
            Categories = new List<string> { "NoSQL", "Cluster" },
            Tags = new List<string> {"Cassandra", "NoSQL", "Scalability", "Hashing"},
            Comments = new List<BlogPostComment>
            {
                new BlogPostComment { Content = "First Comment!", CreatedDate = DateTime.UtcNow,}
            }
        },
        new BlogPost
        {
            Id = redisBlogPosts.GetNextSequence(),
            BlogId = zhangBlog.Id,
            Title = "Couch Db",
            Categories = new List<string> { "NoSQL", "DocumentDB" },
            Tags = new List<string> {"CouchDb", "NoSQL", "JSON"},
            Comments = new List<BlogPostComment>
            {
                new BlogPostComment {Content = "First Comment!", CreatedDate = DateTime.UtcNow,}
            }
        },
    };
 
    yangUser.BlogIds.Add(yangBlog.Id);
    yangBlog.BlogPostIds.AddRange(blogPosts.Where(x => x.BlogId == yangBlog.Id).Map(x => x.Id));
 
    zhangUser.BlogIds.Add(zhangBlog.Id);
    zhangBlog.BlogPostIds.AddRange(blogPosts.Where(x => x.BlogId == zhangBlog.Id).Map(x => x.Id));
 
    redisUsers.Store(yangUser);
    redisUsers.Store(zhangUser);
    redisBlogs.StoreAll(new[] { yangBlog, zhangBlog });
    redisBlogPosts.StoreAll(blogPosts);
}

在方法中,首先在Redis中创建了三个强类型的IRedisTypedClient类型的对象redisUsers,redisBlogs,redisBlogPosts来保存用户信息,博客信息,和文字信息。

 
 
 
 
 
 

C#

 
var yangUser = new User { Id = redisUsers.GetNextSequence(), Name = "Eric Yang" };
1
var yangUser = new User { Id = redisUsers.GetNextSequence(), Name = "Eric Yang" };

在新建用户的时候,因为Id是自增字段,所以直接调用redisUsers这个client的GetNextSequence()方法就可以获得一个自增的Id。

创建完用户之后,接着创建博客信息:

 
 
 
 
 
 

C#

 
var yangBlog = new Blog
{
Id = redisBlogs.GetNextSequence(),
UserId = yangUser.Id,
UserName = yangUser.Name,
Tags = new List<string> { "Architecture", ".NET", "Databases" },
};
1
2
3
4
5
6
7
var yangBlog = new Blog
{
    Id = redisBlogs.GetNextSequence(),
    UserId = yangUser.Id,
    UserName = yangUser.Name,
    Tags = new List<string> { "Architecture", ".NET", "Databases" },
};

该博客有几个标签。

在接着创建该博客上发表的若干篇文章:

 
 
 
 
 
 

C#

 
var blogPosts = new List<BlogPost>
{
new BlogPost
{
Id = redisBlogPosts.GetNextSequence(),
BlogId = yangBlog.Id,
Title = "Memcache",
Categories = new List<string> { "NoSQL", "DocumentDB" },
Tags = new List<string> {"Memcache", "NoSQL", "JSON", ".NET"} ,
Comments = new List<BlogPostComment>
{
new BlogPostComment { Content = "First Comment!", CreatedDate = DateTime.UtcNow,},
new BlogPostComment { Content = "Second Comment!", CreatedDate = DateTime.UtcNow,},
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var blogPosts = new List<BlogPost>
{
    new BlogPost
    {
        Id = redisBlogPosts.GetNextSequence(),
        BlogId = yangBlog.Id,
        Title = "Memcache",
        Categories = new List<string> { "NoSQL", "DocumentDB" },
        Tags = new List<string> {"Memcache", "NoSQL", "JSON", ".NET"} ,
        Comments = new List<BlogPostComment>
        {
            new BlogPostComment { Content = "First Comment!", CreatedDate = DateTime.UtcNow,},
            new BlogPostComment { Content = "Second Comment!", CreatedDate = DateTime.UtcNow,},
        }
    }
}

每一篇文章都有分类和标签,以及评论。

然后需要给user的BlogsIds和blog的BlogPostIds赋值

 
 
 
 
 
 

C#

 
yangUser.BlogIds.Add(yangBlog.Id);
yangBlog.BlogPostIds.AddRange(blogPosts.Where(x => x.BlogId == yangBlog.Id).Map(x => x.Id));
1
2
yangUser.BlogIds.Add(yangBlog.Id);
yangBlog.BlogPostIds.AddRange(blogPosts.Where(x => x.BlogId == yangBlog.Id).Map(x => x.Id));

最后需要把这些信息保存到redis中。

 
 
 
 
 
 

C#

 
//保存用户信息
redisUsers.Store(yangUser);
redisUsers.Store(zhangUser);
//保存博客信息
redisBlogs.StoreAll(new[] { yangBlog, zhangBlog });
//保存所有的文章信息
redisBlogPosts.StoreAll(blogPosts);
1
2
3
4
5
6
7
//保存用户信息
redisUsers.Store(yangUser);
redisUsers.Store(zhangUser);
//保存博客信息
redisBlogs.StoreAll(new[] { yangBlog, zhangBlog });
//保存所有的文章信息
redisBlogPosts.StoreAll(blogPosts);

现在,利用Redis Desktop Manager,可以查看Reidis中存储的数据:

数据准备好了之后,可以实现前面列出的一系列方法了:

显示所有博客

该方法在GetAllBlogs中,实现如下:

 
 
 
 
 
 

C#

 
[Test]
public void Show_a_list_of_blogs()
{
var redisBlogs = redis.As<Blog>();
var blogs = redisBlogs.GetAll();
blogs.PrintDump();
}
1
2
3
4
5
6
7
[Test]
public void Show_a_list_of_blogs()
{
    var redisBlogs = redis.As<Blog>();
    var blogs = redisBlogs.GetAll();
    blogs.PrintDump();
}

只需要调用GetAll方法即可获取内存中的所有指定类型的对象。

输出结果为:

 
 
[
{

Id: 1,
UserId: 1,
UserName: Eric Yang,
Tags:
[
Architecture,
.NET,
Databases
],
BlogPostIds:
[
1,
3
]
},
{
Id: 2,
UserId: 2,
UserName: Fish Zhang,
Tags:
[
Architecture,
.NET,
Databases
],
BlogPostIds:
[
2,
4
]
}
]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
[
    {
        
        Id: 1,
        UserId: 1,
        UserName: Eric Yang,
        Tags:
        [
            Architecture,
            .NET,
            Databases
        ],
        BlogPostIds:
        [
            1,
            3
        ]
    },
    {
        Id: 2,
        UserId: 2,
        UserName: Fish Zhang,
        Tags:
        [
            Architecture,
            .NET,
            Databases
        ],
        BlogPostIds:
        [
            2,
            4
        ]
    }
]

显示最近发表的文章和评论

实现如下:

 
 
 
 
 
 

C#

 
[Test]
public void Show_a_list_of_recent_posts_and_comments()
{
//Get strongly-typed clients
var redisBlogPosts = redis.As<BlogPost>();
var redisComments = redis.As<BlogPostComment>();
{
//To keep this example let's pretend this is a new list of blog posts
var newIncomingBlogPosts = redisBlogPosts.GetAll();

//Let's get back an IList<BlogPost> wrapper around a Redis server-side List.
var recentPosts = redisBlogPosts.Lists["urn:BlogPost:RecentPosts"];
var recentComments = redisComments.Lists["urn:BlogPostComment:RecentComments"];

foreach (var newBlogPost in newIncomingBlogPosts)
{
//Prepend the new blog posts to the start of the 'RecentPosts' list
recentPosts.Prepend(newBlogPost);

//Prepend all the new blog post comments to the start of the 'RecentComments' list
newBlogPost.Comments.ForEach(recentComments.Prepend);
}

//Make this a Rolling list by only keep the latest 3 posts and comments
recentPosts.Trim(0, 2);
recentComments.Trim(0, 2);

//Print out the last 3 posts:
recentPosts.GetAll().PrintDump();
recentComments.GetAll().PrintDump();
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[Test]
public void Show_a_list_of_recent_posts_and_comments()
{
    //Get strongly-typed clients
    var redisBlogPosts = redis.As<BlogPost>();
    var redisComments = redis.As<BlogPostComment>();
    {
        //To keep this example let's pretend this is a new list of blog posts
        var newIncomingBlogPosts = redisBlogPosts.GetAll();
 
        //Let's get back an IList<BlogPost> wrapper around a Redis server-side List.
        var recentPosts = redisBlogPosts.Lists["urn:BlogPost:RecentPosts"];
        var recentComments = redisComments.Lists["urn:BlogPostComment:RecentComments"];
 
        foreach (var newBlogPost in newIncomingBlogPosts)
        {
            //Prepend the new blog posts to the start of the 'RecentPosts' list
            recentPosts.Prepend(newBlogPost);
 
            //Prepend all the new blog post comments to the start of the 'RecentComments' list
            newBlogPost.Comments.ForEach(recentComments.Prepend);
        }
 
        //Make this a Rolling list by only keep the latest 3 posts and comments
        recentPosts.Trim(0, 2);
        recentComments.Trim(0, 2);
 
        //Print out the last 3 posts:
        recentPosts.GetAll().PrintDump();
      recentComments.GetAll().PrintDump();
     }
}

方法中定义了两个key为urn:BlogPost:RecentPosts 和 urn:BlogPostComment:RecentComments的 List对象来保存最近发表的文章和评论:recentPosts.Prepend(newBlogPost)方法表示将新创建的文章插到recentPosts列表的最前面。

Trim方法表示仅保留n个在集合中。

显示博客的标签云

显示博客的标签云方法如下:

 
 
 
 
 
 

C#

 
[Test]
public void Show_a_TagCloud()
{
//Get strongly-typed clients
var redisBlogPosts = redis.As<BlogPost>();
var newIncomingBlogPosts = redisBlogPosts.GetAll();

foreach (var newBlogPost in newIncomingBlogPosts)
{
//For every tag in each new blog post, increment the number of times each Tag has occurred
newBlogPost.Tags.ForEach(x =>
redis.IncrementItemInSortedSet("urn:TagCloud", x, 1));
}

//Show top 5 most popular tags with their scores
var tagCloud = redis.GetRangeWithScoresFromSortedSetDesc("urn:TagCloud", 0, 4);
tagCloud.PrintDump();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[Test]
public void Show_a_TagCloud()
{
    //Get strongly-typed clients
    var redisBlogPosts = redis.As<BlogPost>();
    var newIncomingBlogPosts = redisBlogPosts.GetAll();
 
    foreach (var newBlogPost in newIncomingBlogPosts)
    {
        //For every tag in each new blog post, increment the number of times each Tag has occurred
        newBlogPost.Tags.ForEach(x =>
            redis.IncrementItemInSortedSet("urn:TagCloud", x, 1));
    }
 
    //Show top 5 most popular tags with their scores
    var tagCloud = redis.GetRangeWithScoresFromSortedSetDesc("urn:TagCloud", 0, 4);
    tagCloud.PrintDump();
}

显示标签云的实现,用到了redis中的SortedSet,IncrementItemInSortedSet表示如果有相同的话,值加一,GetRangeWithScoresFromSortedSetDesc方法,获取某一key的前5个对象。

显示所有的分类

显示所有的分类用到了Set对象。

 
 
 
 
 
 

C#

 
[Test]
public void Show_all_Categories()
{
var redisBlogPosts = redis.As<BlogPost>();
var blogPosts = redisBlogPosts.GetAll();

foreach (var blogPost in blogPosts)
{
blogPost.Categories.ForEach(x =>
redis.AddItemToSet("urn:Categories", x));
}

var uniqueCategories = redis.GetAllItemsFromSet("urn:Categories");
uniqueCategories.PrintDump();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[Test]
public void Show_all_Categories()
{
    var redisBlogPosts = redis.As<BlogPost>();
    var blogPosts = redisBlogPosts.GetAll();
 
    foreach (var blogPost in blogPosts)
    {
        blogPost.Categories.ForEach(x =>
                redis.AddItemToSet("urn:Categories", x));
    }
 
    var uniqueCategories = redis.GetAllItemsFromSet("urn:Categories");
    uniqueCategories.PrintDump();
}

显示文章以及其评论

实现如下:

 
 
 
 
 
 

C#

 
[Test]
public void Show_post_and_all_comments()
{
//There is nothing special required here as since comments are Key Value Objects
//they are stored and retrieved with the post
var postId = 1;
var redisBlogPosts = redis.As<BlogPost>();
var selectedBlogPost = redisBlogPosts.GetById(postId.ToString());

selectedBlogPost.PrintDump();
}

1
2
3
4
5
6
7
8
9
10
11
[Test]
public void Show_post_and_all_comments()
{
    //There is nothing special required here as since comments are Key Value Objects
    //they are stored and retrieved with the post
    var postId = 1;
    var redisBlogPosts = redis.As<BlogPost>();
    var selectedBlogPost = redisBlogPosts.GetById(postId.ToString());
 
    selectedBlogPost.PrintDump();
}

只需要把postId传进去就可以通过GetById的方法获取内存中的对象.

添加评论

首先根据PostId获取BlogPost,然后在Comment属性中添加一个BlogPostComment对象,然后在保存改BlogPost.

 
 
 
 
 
 

C#

 
[Test]
public void Add_comment_to_existing_post()
{
var postId = 1;
var redisBlogPosts = redis.As<BlogPost>();
var blogPost = redisBlogPosts.GetById(postId.ToString());
blogPost.Comments.Add(
new BlogPostComment { Content = "Third Post!", CreatedDate = DateTime.UtcNow });
redisBlogPosts.Store(blogPost);

var refreshBlogPost = redisBlogPosts.GetById(postId.ToString());
refreshBlogPost.PrintDump();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
[Test]
public void Add_comment_to_existing_post()
{
    var postId = 1;
    var redisBlogPosts = redis.As<BlogPost>();
    var blogPost = redisBlogPosts.GetById(postId.ToString());
    blogPost.Comments.Add(
        new BlogPostComment { Content = "Third Post!", CreatedDate = DateTime.UtcNow });
    redisBlogPosts.Store(blogPost);
 
    var refreshBlogPost = redisBlogPosts.GetById(postId.ToString());
    refreshBlogPost.PrintDump();
}

显示分类以及分类对应的文章

 
 
 
 
 
 

C#

 
[Test]
public void Show_all_Posts_for_the_DocumentDB_Category()
{
var redisBlogPosts = redis.As<BlogPost>();
var newIncomingBlogPosts = redisBlogPosts.GetAll();

foreach (var newBlogPost in newIncomingBlogPosts)
{
//For each post add it's Id into each of it's 'Cateogry > Posts' index
newBlogPost.Categories.ForEach(x =>
redis.AddItemToSet("urn:Category:" + x, newBlogPost.Id.ToString()));
}

//Retrieve all the post ids for the category you want to view
var documentDbPostIds = redis.GetAllItemsFromSet("urn:Category:DocumentDB");

//Make a batch call to retrieve all the posts containing the matching ids
//(i.e. the DocumentDB Category posts)
var documentDbPosts = redisBlogPosts.GetByIds(documentDbPostIds);

documentDbPosts.PrintDump();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[Test]
public void Show_all_Posts_for_the_DocumentDB_Category()
{
    var redisBlogPosts = redis.As<BlogPost>();
    var newIncomingBlogPosts = redisBlogPosts.GetAll();
 
    foreach (var newBlogPost in newIncomingBlogPosts)
    {
        //For each post add it's Id into each of it's 'Cateogry > Posts' index
        newBlogPost.Categories.ForEach(x =>
                redis.AddItemToSet("urn:Category:" + x, newBlogPost.Id.ToString()));
    }
 
    //Retrieve all the post ids for the category you want to view
    var documentDbPostIds = redis.GetAllItemsFromSet("urn:Category:DocumentDB");
 
    //Make a batch call to retrieve all the posts containing the matching ids
    //(i.e. the DocumentDB Category posts)
    var documentDbPosts = redisBlogPosts.GetByIds(documentDbPostIds);
 
    documentDbPosts.PrintDump();
}

这里首先把所有的文章按照标签新建Set,把相同的分类的文章放到一个Set中,最后根据key即可查找到相应的集合。

总结

本文利用一个简单的博客系统,简要介绍了如何利用Redis存储和获取复杂的数据。由于本文主要为了演示如何与Redis进行交互,所以实体设计的很简陋,没有按照DDD的思想进行设计,在某些设计方面没有遵循前文浅谈依赖注入中使用的原理和方法,后面会写文章对该系统进行重构以使之更加完善。

希望本文对您了解如何利用Redis存储复杂对象有所帮助。

参考资料

  1. Designing NoSql Database
  2. Migrations Using Schemaless NoSql
  3. That No SQL Thing: The relational modeling anti pattern in document databases

.NET中使用Redis(二)的更多相关文章

  1. .NET中使用Redis (二)

    很久以前写了一篇文章 .NET中使用Redis 介绍了如何安装Redis服务端,以及如何在.NET中调用Redis读取数据.本文简单介绍如何设计NoSQL数据库,以及如何使用Redis来存储对象. 和 ...

  2. 转:.NET中使用Redis (二)

    原文来自于:http://blog.jobbole.com/83824/ 原文出处: 寒江独钓   欢迎分享原创到伯乐头条 很久以前写了一篇文章 .NET中使用Redis 介绍了如何安装Redis服务 ...

  3. 分布式数据存储 之 Redis(二) —— spring中的缓存抽象

    分布式数据存储 之 Redis(二) -- spring中的缓存抽象 一.spring boot 中的 StringRedisTemplate 1.StringRedisTemplate Demo 第 ...

  4. (二)如何在.net中使用Redis

    Step1:使用NuGet工具安装Redis C# API,这里有多个API我们可以使用其中一个:

  5. Redis学习笔记之二 :在Java项目中使用Redis

    成功配置redis之后,便来学习使用redis.首先了解下redis的数据类型. Redis的数据类型 Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set( ...

  6. C#中使用Redis学习二 在.NET4.5中使用redis hash操作

    上一篇>> 摘要 上一篇讲述了安装redis客户端和服务器端,也大体地介绍了一下redis.本篇着重讲解.NET4.0 和 .NET4.5中如何使用redis和C# redis操作哈希表. ...

  7. 【转】C#中使用Redis学习二 在.NET4.5中使用redis hash操作

    摘要 上一篇讲述了安装redis客户端和服务器端,也大体地介绍了一下redis.本篇着重讲解.NET4.0 和 .NET4.5中如何使用redis和C# redis操作哈希表.并且会将封装的一些代码贴 ...

  8. ABP中使用Redis Cache(1)

    本文将讲解如何在ABP中使用Redis Cache以及使用过程中遇到的各种问题.下面就直接讲解使用步骤,Redis环境的搭建请直接网上搜索. 使用步骤: 一.ABP环境搭建 到http://www.a ...

  9. 在java中使用redis

    在java中使用redis很简单,只需要添加jedist.jar,通过它的api就可以了.而且,api和redis的语法几乎完全相同.以下简单的测试: 参考:http://www.runoob.com ...

随机推荐

  1. 开源NetWorkSocket通讯组件

    开源NetWorkSocket通讯组件   前言 在<化茧成蝶,开源NetWorkSocket通讯组件>发表之后,收到大家很多个star,在此感谢!更可贵的是,一些网友提出了许多好建议,经 ...

  2. Directx11学习笔记【三】 第一个D3D11程序

    在先前的解决方案中新建一个新的Win32项目FirstD3D11Demo.在写代码之前,我们必须先添加dx11所需要的库.为了链接dx库,右键项目选择属性->vc++目录,在包含目录中添加你所安 ...

  3. Java程序猿从底层到CTO的技术路线图

    首先.附一张图片展示所在各个阶段的工作职能: 其次.文字型描写叙述所在各个阶段的工作职能: Java程序猿 高级特性 反射.泛型.凝视符.自己主动装箱和拆箱.枚举类.可变參数.可变返回类型.增强循环. ...

  4. C日常语言实践中小(四)——勇者斗恶龙

    勇者斗恶龙 愿你的国有n龙的头,你想聘请骑士杀死它(全部的头). 村里有m个骑士能够雇佣,一个能力值为x的骑士能够砍掉恶龙一个致敬不超过x的头,且须要支付x个金币. 怎样雇佣骑士才干砍掉恶龙的全部头, ...

  5. flashfxp3.41中文版注册码:(适合最新版本)

    推荐(尚未被封的 Realkey) FLASHFXPvACq2ssbvAAAAAC1W7cJKQTzmx77zmqJICvA7d3WnU tWNXdrp8YuERRFdIvXfOPbcpABkVix2 ...

  6. ZenCoding for EmEditor Snippets 的安装

    ZenCoding for EmEditor的安装 你可以从这里下载所需文件Library under the Snippets category.安装前请确认你的EmEditor内置有代码片段(Sn ...

  7. Oracle中merge into的使用 (转)

    该命令使用一条语句从一个或者多个数据源中完成对表的更新和插入数据. ORACLE 9i 中,使用此命令必须同时指定UPDATE 和INSERT 关键词,ORACLE 10g 做了如下改动. 1.ins ...

  8. RH133读书笔记(6) - Lab 6 Adding New Filesystems to the Filesystem Tree

    Lab 6 Adding New Filesystems to the Filesystem Tree Goal: Develop skills and knowlege related to par ...

  9. 引用类型之object类型

    object类型有两种创建方法,第一种是直接创建法: var person=new Object(); person.name = "Nicholas"; person.age = ...

  10. [DEEP LEARNING An MIT Press book in preparation]Linear algebra

    线性代数是数学的一个重要分支,它经常被施加到project问题,要了解学习和工作深入研究的深度,因此,对于线性代数的深刻理解是非常重要的.下面是我总结的距离DL book性代数中抽取出来的比較有意思的 ...