上一篇讲解了如何在ABP中使用Redis Cache,虽然能够正常的访问Redis,但是Redis里的信息无法同步更新。本文将讲解如何实现Redis Cache与实体同步更新。要实现数据的同步更新,我们能够想到的最基本、最简单、也是复杂的方法:在每一个增、删、改的方法里添加同步缓存的代码,说它最简单,是因为技术实现非常简单,就是在每一个方法里多加一句代码;说它复杂,是因为这样的写的话,会出现很多重复的代码,并且容易出现遗漏,维护起来很不方便。那么有没有一种更简单的方式呢,在数据出现变化后,触发一个事件,主动通知订阅者执行相关操作呢?答案是肯定的,我们可以通过注册领域事件来实现,在ABP中,实体增加、删除、修改后会触发相关事件,只要注册就可以了。要注册事件,有两种方式可以实现,第一是自动注册,实现IEventHandler就可以了,ABP会自动注册;第二是通过IEventBus的Register方法手动注册。ABP中推荐使用自动注册的方式实现,本文也会采用第一种方式实现。下面我们就来看具体的实现方式,首先增加一个处理缓存同步的接口ICacheSyncService,代码如下(本文的代码是在上一篇的基础之上编写的):

作者:loyldg 出处:http://www.cnblogs.com/loyldg/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。如有问题,可以邮件:loyldg@126.com 联系我,非常感谢。

ICacheSyncService.cs

  1. public interface ICacheSyncService
  2. {
  3. void Add<TEntity>(TEntity entity) where TEntity : class, IEntity<int>;
  4. void Remove<TEntity>(int id) where TEntity : class, IEntity<int>;
  5. void Update<TEntity>(TEntity entity) where TEntity : class, IEntity<int>;
  6. }

CacheSyncService.cs

  1. public class CacheSyncService : ICacheSyncService, ISingletonDependency
  2. {
  3. public ICacheService CacheService { get; set; }
  4.  
  5. public void Add<TEntity>(TEntity entity) where TEntity : class, IEntity<int>
  6. {
  7. CacheService.Set(entity.Id, entity);
  8. }
  9.  
  10. public void Remove<TEntity>(int id) where TEntity : class, IEntity<int>
  11. {
  12. CacheService.Remove<int, TEntity>(id);
  13. }
  14.  
  15. public void Update<TEntity>(TEntity entity) where TEntity : class, IEntity<int>
  16. {
  17. CacheService.Set(entity.Id, entity);
  18. }
  19. }

第二增加一个处理实体事件的泛型基类EntityChangedHandlerBase<TEntity>,代码如下:

  1. public abstract class EntityChangedHandlerBase<TEntity>:
  2. ISingletonDependency,
  3. IEventHandler<EntityCreatedEventData<TEntity>>,
  4. IEventHandler<EntityDeletedEventData<TEntity>>,
  5. IEventHandler<EntityUpdatedEventData<TEntity>>
  6. where TEntity : class, IEntity<int>
  7. {
  8. public ICacheSyncService CacheSyncService { get; set; }
  9.  
  10. public virtual void HandleEvent(EntityCreatedEventData<TEntity> eventData)
  11. {
  12. CacheSyncService.Add(eventData.Entity);
  13. }
  14.  
  15. public virtual void HandleEvent(EntityDeletedEventData<TEntity> eventData)
  16. {
  17. CacheSyncService.Remove<TEntity>(eventData.Entity.Id);
  18. }
  19.  
  20. public virtual void HandleEvent(EntityUpdatedEventData<TEntity> eventData)
  21. {
  22. CacheSyncService.Update(eventData.Entity);
  23. }
  24. }

第三,增加一个需要进行缓存同步的实体类,继承自EntityChangedHandlerBase<TEntity>就可以了,不需要编写任何代码,如果有特殊情况,可以重新HandleEvent方法,代码如下:

  1. public class ArticleChangedHandler : EntityChangedHandlerBase<Article>
  2. {
  3.  
  4. }

至此,缓存同步的全部代码已编写完成,我们运行来看看效果:

我们添加文章后,什么操作也不做,直接到Redis里查看是否有新增的数据,如果有新增的数据表示缓存能够自动更新了(删除和修改是一样的,这里就不编写相关代码了),直接看单元测试代码。

  1. public class CacheSync_Tests : UsingRedisInAbpTestBase
  2. {
  3. [Fact]
  4. public void Test_Entity_Changed_Event()
  5. {
  6. LoginAsHostAdmin();
  7. var title = "unit_test";
  8. var articleId = ;
  9. var service = Resolve<TestCacheSyncService>();
  10. service.IsCreatedEventFired.ShouldBeFalse();
  11. service.IsUpdatedEventFired.ShouldBeFalse();
  12. service.IsDeletedEventFired.ShouldBeFalse();
  13.  
  14. //新增文章测试
  15. UsingDbContext(c =>c.Articles.Add(new Article {Title = title}));
  16.  
  17. service.IsCreatedEventFired.ShouldBe(true);
  18.  
  19. //更新文章测试
  20. UsingDbContext(c =>
  21. {
  22. var article=c.Articles.First();
  23. c.Articles.Attach(article);
  24. article.Title = "new_title";
  25. });
  26. service.IsUpdatedEventFired.ShouldBe(true);
  27.  
  28. //删除文章测试
  29. UsingDbContext(c =>
  30. {
  31. var article = c.Articles.First();
  32. c.Articles.Remove(article);
  33. });
  34. service.IsDeletedEventFired.ShouldBe(true);
  35. }
  36. }

TestSyncCache.cs代码:

  1. public class TestCacheSyncService : ICacheSyncService
  2. {
  3. public bool IsCreatedEventFired { get; set; }
  4. public bool IsDeletedEventFired { get; set; }
  5. public bool IsUpdatedEventFired { get; set; }
  6. public void Add<TEntity>(TEntity entity) where TEntity : class, IEntity<int>
  7. {
  8. IsCreatedEventFired = true;
  9.  
  10. }
  11.  
  12. public void Remove<TEntity>(int id) where TEntity : class, IEntity<int>
  13. {
  14. IsDeletedEventFired = true;
  15.  
  16. }
  17.  
  18. public void Update<TEntity>(TEntity entity) where TEntity : class, IEntity<int>
  19. {
  20. IsUpdatedEventFired = true;
  21. }
  22. }

通过以上方式已实现了ABP中Redis缓存的读取和设置,也实现了缓存的同步更新,如果要在ABP中使用其他缓存也是一样的,只需要把缓存实现部分换成其他缓存就行。本文的所有源代码下载地址:

http://files.cnblogs.com/files/loyldg/UsingRedisInAbp_2.src.rar

作者:loyldg 出处:http://www.cnblogs.com/loyldg/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。如有问题,可以邮件:loyldg@126.com 联系我,非常感谢。

ABP中使用Redis Cache(2)的更多相关文章

  1. ABP中使用Redis Cache(1)

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

  2. Azure Redis Cache

    将于 2014 年 9 月 1 日停止Azure Shared Cache服务,因此你需要在该日期前迁移到 Azure Redis Cache.Azure Redis Cache包含以下两个层级的产品 ...

  3. Spring Boot 揭秘与实战(二) 数据缓存篇 - Redis Cache

    文章目录 1. Redis Cache 集成 2. 源代码 本文,讲解 Spring Boot 如何集成 Redis Cache,实现缓存. 在阅读「Spring Boot 揭秘与实战(二) 数据缓存 ...

  4. ABP module-zero +AdminLTE+Bootstrap Table+jQuery权限管理系统第十五节--缓存小结与ABP框架项目中 Redis Cache的实现

    返回总目录:ABP+AdminLTE+Bootstrap Table权限管理系统一期 缓存 为什么要用缓存 为什么要用缓存呢,说缓存之前先说使用缓存的优点. 减少寄宿服务器的往返调用(round-tr ...

  5. 缓存与ABP Redis Cache

    缓存与ABP Redis Cache 为什么要用缓存 为什么要用缓存呢,说缓存之前先说使用缓存的优点. 减少寄宿服务器的往返调用(round-trips). 如果缓存在客户端或是代理,将减少对服务器的 ...

  6. 使用abp的 redis cache

    top 使用abp的 redis cache -1. 在微软维护的github项目的release里找到redis的windows版本 64位 大约5M,安装,安装,然后在安装目录找到redis.wi ...

  7. .NET中使用Redis (二)

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

  8. 如何在ASP.NET Core中使用Redis

    注:本文提到的代码示例下载地址> https://code.msdn.microsoft.com/How-to-use-Redis-in-ASPNET-0d826418 Redis是一个开源的内 ...

  9. Azure Redis Cache (1) 入门

    <Windows Azure Platform 系列文章目录> Microsoft Azure Redis Cache基于流行的开源Redis Cache. 1.功能 Redis 是一种高 ...

随机推荐

  1. Android-Activity-Dialog theme touch outsize

    最近遇到一个蛋疼的问题: 一个Activity,主题设置成 Dialog 然后点击外面要求这个Activity 不能关闭. 这下好了,直接在 style 的 theme 里面加一个属性就好了. 加上去 ...

  2. for循环或Repeat里面对某个字段进行复杂处理的解决方案

    在后台用一个方法处理

  3. 【源码】Word转PDF V1.0.1 小软件,供新手参考

    昨天有一朋友让我帮忙找一款Word转PDF的软件,今天自己捣鼓出点成果封装个Helper供大家使用~ 开源地址:https://github.com/dunitian/WordConvertPDF 软 ...

  4. jQuery源码分析系列(37) : Ajax 总结

    综合前面的分析,我们总结如下3大块: jQuery1.5以后,AJAX模块提供了三个新的方法用于管理.扩展AJAX请求 前置过滤器 jQuery. ajaxPrefilter 请求分发器 jQuery ...

  5. js中用tagname和id获取元素的3种方法

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. Ruby之基础介绍(二)

    前言 上一篇我们简单介绍了下Ruby,这一节我们开始正式步入Ruby的世界,一探究竟. Ruby特点 (1)面向对象支持. (2)动态语言:我们可以修改已经定义过的类,也可以为现有类添加实例方法. ( ...

  7. JavaScript之自我总结篇

    最近在看汤姆大叔的"深入理解JavaScript系列",写得真的不错,对于我而言特别是12章到19章,因为大叔研究的点,就主要是从底层来研究JavaScript为什么会出现钟种特有 ...

  8. UWP开发之Mvvmlight实践一:如何在项目中添加使用Mvvmlight(图文详解)

    最近一直在做UWP开发,为了节省成本等等接触到MVVMlight,觉得有必要发点时间研究它的用法与实现原理才行.如果有问题的地方或者有好的建议欢迎提出来. 随着移动开发的热门,Mvvmlight在An ...

  9. MySQL线程池

    MySQL线程池只在Percona,MariaDB,Oracle MySQL企业版中提供.Oracle MySQL社区版并不提供. 在传统方式下,MySQL线程调度方式有两种:每个连接一个线程(one ...

  10. ((uchar*)(Img1->imageData + Img1->widthStep*pt.y))[pt.x] 的 具体含义

    widthstep是指图像每行所占的字节数. 主要要和width区别: width是表示图像的每行像素数,widthStep指表示存储一行像素需要的字节数. 在OpenCV里边,widthStep必须 ...