上一篇講解了如何在ABP中使用Redis Cache,雖然能夠正常的訪問Redis,但是Redis里的信息無法同步更新。本文將講解如何實現Redis Cache與實體同步更新。要實現數據的同步更新,我們能夠想到的最基本、最簡單、也是復雜的方法:在每一個增、刪、改的方法里添加同步緩存的代碼,說它最簡單,是因為技術實現非常簡單,就是在每一個方法里多加一句代碼;說它復雜,是因為這樣的寫的話,會出現很多重復的代碼,並且容易出現遺漏,維護起來很不方便。那么有沒有一種更簡單的方式呢,在數據出現變化后,觸發一個事件,主動通知訂閱者執行相關操作呢?答案是肯定的,我們可以通過注冊領域事件來實現,在ABP中,實體增加、刪除、修改后會觸發相關事件,只要注冊就可以了。要注冊事件,有兩種方式可以實現,第一是自動注冊,實現IEventHandler就可以了,ABP會自動注冊;第二是通過IEventBus的Register方法手動注冊。ABP中推薦使用自動注冊的方式實現,本文也會采用第一種方式實現。下面我們就來看具體的實現方式,首先增加一個處理緩存同步的接口ICacheSyncService,代碼如下(本文的代碼是在上一篇的基礎之上編寫的):
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>; }
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> { }
至此,緩存同步的全部代碼已編寫完成,我們運行來看看效果:


我們添加文章后,什么操作也不做,直接到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; } }
通過以上方式已實現了ABP中Redis緩存的讀取和設置,也實現了緩存的同步更新,如果要在ABP中使用其他緩存也是一樣的,只需要把緩存實現部分換成其他緩存就行。本文的所有源代碼下載地址:
http://files.cnblogs.com/files/loyldg/UsingRedisInAbp_2.src.rar
