zoukankan      html  css  js  c++  java
  • ABP中使用Redis Cache(2)

         上一篇讲解了如何在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

     public interface ICacheSyncService
        {
            void Add<TEntity>(TEntity entity) where TEntity : class, IEntity<int>;
            void Remove<TEntity>(int id) where TEntity : class, IEntity<int>;
            void Update<TEntity>(TEntity entity) where TEntity : class, IEntity<int>;
        }
    View Code

    CacheSyncService.cs

    public class CacheSyncService : ICacheSyncService, ISingletonDependency
        {
            public ICacheService CacheService { get; set; }
    
            public void Add<TEntity>(TEntity entity) where TEntity : class, IEntity<int>
            {
                CacheService.Set(entity.Id, entity);
            }
    
            public void Remove<TEntity>(int id) where TEntity : class, IEntity<int>
            {
                CacheService.Remove<int, TEntity>(id);
            }
    
            public void Update<TEntity>(TEntity entity) where TEntity : class, IEntity<int>
            {
                CacheService.Set(entity.Id, entity);
            }
        }

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

    public abstract class EntityChangedHandlerBase<TEntity>:
            ISingletonDependency,
            IEventHandler<EntityCreatedEventData<TEntity>>,
            IEventHandler<EntityDeletedEventData<TEntity>>,
            IEventHandler<EntityUpdatedEventData<TEntity>>
            where TEntity : class, IEntity<int>
        {
            public ICacheSyncService CacheSyncService { get; set; }
    
            public virtual void HandleEvent(EntityCreatedEventData<TEntity> eventData)
            {
                CacheSyncService.Add(eventData.Entity);
            }
    
            public virtual void HandleEvent(EntityDeletedEventData<TEntity> eventData)
            {
                CacheSyncService.Remove<TEntity>(eventData.Entity.Id);
            }
    
            public virtual void HandleEvent(EntityUpdatedEventData<TEntity> eventData)
            {
                CacheSyncService.Update(eventData.Entity);
            }
        }

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

    public class ArticleChangedHandler : EntityChangedHandlerBase<Article>
        {
            
        }
    View Code

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

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

    public class CacheSync_Tests : UsingRedisInAbpTestBase
        {
             [Fact]
            public void Test_Entity_Changed_Event()
            {
                 LoginAsHostAdmin();
                 var title = "unit_test";
                 var articleId = 0;
                 var service = Resolve<TestCacheSyncService>();
                 service.IsCreatedEventFired.ShouldBeFalse();
                 service.IsUpdatedEventFired.ShouldBeFalse();
                 service.IsDeletedEventFired.ShouldBeFalse();
                 
                 //新增文章测试
                 UsingDbContext(c =>c.Articles.Add(new Article {Title = title}));
                 
                 service.IsCreatedEventFired.ShouldBe(true);
    
                 //更新文章测试
                 UsingDbContext(c =>
                 {
                     var article=c.Articles.First();
                     c.Articles.Attach(article);
                     article.Title = "new_title";
                 });
                 service.IsUpdatedEventFired.ShouldBe(true);
    
                 //删除文章测试
                 UsingDbContext(c =>
                 {
                     var article = c.Articles.First();
                     c.Articles.Remove(article);                 
                 });
                 service.IsDeletedEventFired.ShouldBe(true);
            }
        }

    TestSyncCache.cs代码:

     public class TestCacheSyncService : ICacheSyncService
        {
            public bool IsCreatedEventFired { get; set; }
            public bool IsDeletedEventFired { get; set; }
            public bool IsUpdatedEventFired { get; set; }
            public void Add<TEntity>(TEntity entity) where TEntity : class, IEntity<int>
            {
                IsCreatedEventFired = true;
                
            }
    
            public void Remove<TEntity>(int id) where TEntity : class, IEntity<int>
            {
                IsDeletedEventFired = true;
    
            }
    
            public void Update<TEntity>(TEntity entity) where TEntity : class, IEntity<int>
            {
                IsUpdatedEventFired = true;
            }
        }  
    View Code

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

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

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

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

  • 相关阅读:
    C# 实现任务栏图标程序
    C#实现的木马之客户端
    sql基本语法
    水晶报表引用DataSet做数据源
    解决多线程操作控件时可能出现的异常:“在某个线程上创建的控件不能成为在另一个线程上创建的控件的父级”
    电子书籍制作工具软件大全
    C#实现的木马之服务端
    2进制、8进制、10进制、16进制...各种进制间的轻松转换
    VC# .Net中使用Crystal Report水晶报表
    P2P技术学习
  • 原文地址:https://www.cnblogs.com/loyldg/p/using-redis-in-abp-2.html
Copyright © 2011-2022 走看看