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 联系我,非常感谢。
posted @ 2016-01-21 13:25  loyldg  阅读(4071)  评论(1编辑  收藏  举报