C#IUnitOfWork,IRepository和IMemoryCache [ASP.Net核心]

时间:2018-03-12 19:09:36

标签: caching asp.net-core repository-pattern unit-of-work

我的目标是放入我的数据缓存。我使用AspBoilerPlate作为我的代码的灵感。

我的WebApi使用Asp.net Core。

GitHub的

我在GitHub上创建了一个分支,以获取更多详细信息:

CacheRepository

public class CacheRepository<TEntity, TPrimaryKey> : Repository<TEntity, TPrimaryKey>, ICacheRepository<TEntity, TPrimaryKey>
  where TEntity : class, IEntity<TPrimaryKey>
{
    private readonly IMemoryCache _memoryCache;

    public CacheRepository(DbContext dbContext, IMemoryCache memoryCache)
        : base(dbContext)
    {
        _memoryCache = memoryCache;
    }

    public override TEntity FirstOrDefault(TPrimaryKey id)
    {
        if (!_memoryCache.TryGetValue(GetCacheKey(id), out TEntity result))
        {
            result = base.FirstOrDefault(id);
            if (result != null)
            {
                PutInCache(result);
            }
        }

        return result;
    }

    public override void Delete(Expression<Func<TEntity, bool>> predicate)
    {
        foreach (var entity in GetAll().Where(predicate).ToList())
        {
            Delete(entity);
        }
    }

    public override void Delete(TEntity entity)
    {
        base.Delete(entity);
        RemoveFromCache(entity.Id);
    }

    public override void Delete(TPrimaryKey id)
    {
        base.Delete(id);
        RemoveFromCache(id);
    }

    public override Task DeleteAsync(Expression<Func<TEntity, bool>> predicate)
    {
        return Task.Run(() => Delete(predicate));
    }

    public override Task DeleteAsync(TEntity entity)
    {
        return Task.Run(() => Delete(entity));
    }

    public override Task DeleteAsync(TPrimaryKey id)
    {
        return Task.Run(() => Delete(id));
    }

    public override Task<TEntity> FirstOrDefaultAsync(TPrimaryKey id)
    {
        return _memoryCache.GetOrCreateAsync(
            GetCacheKey(id),
            e => base.FirstOrDefaultAsync(id)
        );
    }

    public override List<TEntity> GetAllList()
    {
        var entities = GetAllEntitiesFromCache();
        if (entities == null)
        {
            entities = base.GetAllList();
            foreach (var entity in entities)
            {
                PutInCache(entity);
            }
        }

        return entities.ToList();
    }

    public override async Task<List<TEntity>> GetAllListAsync()
    {
        var entities = GetAllEntitiesFromCache();
        if (entities == null)
        {
            entities = await base.GetAllListAsync();
            foreach (var entity in entities)
            {
                PutInCache(entity);
            }
        }

        return entities.ToList();
    }

    public override TEntity Get(TPrimaryKey id)
    {
        return _memoryCache.GetOrCreate(
            GetCacheKey(id),
            e => base.Get(id)
        );
    }

    public override Task<TEntity> GetAsync(TPrimaryKey id)
    {
        return _memoryCache.GetOrCreate(
            GetCacheKey(id),
            e => base.GetAsync(id)
        );
    }

    public override TEntity Insert(TEntity entity)
    {
        return PutInCache(base.Insert(entity));
    }

    public override TPrimaryKey InsertAndGetId(TEntity entity)
    {
        return Insert(entity).Id;
    }

    public override Task<TPrimaryKey> InsertAndGetIdAsync(TEntity entity)
    {
        return Task.FromResult(InsertAndGetId(entity));
    }

    public override Task<TEntity> InsertAsync(TEntity entity)
    {
        return Task.FromResult(Insert(entity));
    }

    public override TEntity Update(TEntity entity)
    {
        return UpdateInCache(base.Update(entity));
    }

    public override TEntity Update(TPrimaryKey id, Action<TEntity> updateAction)
    {
        return UpdateInCache(base.Update(id, updateAction));
    }

    public override Task<TEntity> UpdateAsync(TEntity entity)
    {
        return Task.FromResult(Update(entity));
    }

    public override async Task<TEntity> UpdateAsync(TPrimaryKey id, Func<TEntity, Task> updateAction)
    {
        return UpdateInCache(await base.UpdateAsync(id, updateAction));
    }

    #region Private

    private TEntity PutInCache(TEntity entity)
    {
        return _memoryCache.Set(GetCacheKey(entity.Id), entity);
    }

    private void RemoveFromCache(TPrimaryKey id)
    {
        _memoryCache.Remove(GetCacheKey(id));
    }

    private TEntity UpdateInCache(TEntity entity)
    {
        RemoveFromCache(entity.Id);
        return PutInCache(entity);
    }



    private string GetCacheKey(TPrimaryKey id)
    {
        return typeof(TEntity).FullName + id;
    }

    private IList<TEntity> GetAllEntitiesFromCache()
    {
        return _memoryCache.Get<List<TEntity>>(typeof(TEntity));
    }
    #endregion
}

我的问题:

我有很多问题要问我的CacheRepository,但我不得不减少它才能发布我的帖子。

=&GT;在UnitOfWork.SubmitChanges之前在Insert / Edit / Delete上直接添加/编辑/删除CacheRepository是一件好事吗?

如果您对CacheRepository有任何建议或建议,请分享,我真的想了解更多相关内容。

1 个答案:

答案 0 :(得分:1)

通常在进程尚未完成时从缓存中删除某些内容会导致麻烦。目前还不确定更改是否会生效bc即使使用orm,dbms也会为您做出决定。在从给定缓存中删除对象之前,您可以等待进程完成,最终将深入挖掘所有异常和读取的内容。

当我在你的代码中挖掘一点(非常干净,+1)时,我想到的其他事情如下:

  1. Generic-Repository-Pattern是anti-pattern。我也喜欢将它用于简单的场景,但它并不是必需的。
  2. 您的CacheRepository现在不仅负责缓存,还可以对数据库的CRUD操作负责。这违反了SRP
  3. CacheUnitOfWork不仅是一个缓存和一个工作单元,它还是一个工厂,一个存储库,还有另一层已经实现的功能。同样,这是针对SRP的。
  4. IMemoryCache is part of a library the belongs to AspNetCore。您正在使用它在您自己的实现中,而它已经包装了一个将内容放入并发字典的逻辑。您可以在控制器中简单地使用它,在必要时添加/更新或删除操作中的项目。
  5. 工作单元格式in this scenario is not necessary。使用您的db-context,在使用context.Set<TEnitity>()...并将所有内容包装在存储库中时,您已经拥有了它。
  6. 抽象是好事,但有时它们也可能非常糟糕。

    我知道这就是为什么我阅读了很多关于这些问题的事情的斗争,我遇到了一个很好的解决方案。 CQRS,调解员和DDD类服务。

    我还建议您查看AutoFac for IoC and DI。现在手动执行的很多事情(比如工厂创建类型)可以使用assembly scanning自动完成。它甚至可以与.NET Core native IoC集成。

    希望它可以帮助你获得一些想法。