加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 存储库模式和本地缓存

发布时间:2020-12-15 05:40:46 所属栏目:百科 来源:网络整理
导读:我有以下接口/类: public interface IUnitOfWork : IDisposable{ event EventHandlerEventArgs Saved; DbSetT SetT() where T : class; DbEntityEntryT EntryT(T entity) where T : class; void Commit();} 以及存储库的实现: public class CachedSqlRepos
我有以下接口/类:
public interface IUnitOfWork : IDisposable
{
    event EventHandler<EventArgs> Saved;
    DbSet<T> Set<T>() where T : class;
    DbEntityEntry<T> Entry<T>(T entity) where T : class;
    void Commit();
}

以及存储库的实现:

public class CachedSqlRepository<T,TKey,TContext> : ICacheRepository<T,TContext>
    where T : class
    where TContext : DbContext,IDisposable,new()
{
    //A list of the Navigation Properties to include
    private readonly Expression<Func<T,object>>[] _NavigationProperties;

    public CachedSqlRepository(params Expression<Func<T,object>>[] navigationProperties)
    {
        _NavigationProperties = navigationProperties;
        using (TContext dbContext = new TContext()) //Fetch the List of Entities
        {
            RefreshCache(dbContext);
        }
    }
    /// <summary>
    /// The Collection of Items in the database
    /// Note this is a Cache,but should replicate whats in the DB
    /// </summary>
    public IList<T> Items { get; private set; }

    public bool Any(Func<T,bool> predicate)
    {
        return Items.Any(predicate);
    }

    public void RefreshCache(DbContext context)
    {
        switch (_NavigationProperties.Length)
        {
            case 0:
                Items = context.Set<T>().ToList();
                break;
            case 1:
                Items = context.Set<T>().Include(_NavigationProperties[0]).ToList();
                break;
           //more here
        }
    }

    /// <summary>
    /// Refresh the internal cache
    /// </summary>
    public void RefreshCache()
    {
        using (TContext dbContext = new TContext())
        {
            RefreshCache(dbContext);
        }
    }

    public IEnumerable<T> FilterBy(Func<T,bool> predicate)
    {
        return Items.Where(predicate);
    }

    public T Add(T entity)
    {
        T newEntity;
        using (TContext dbContext = new TContext())
        {
            newEntity = dbContext.Set<T>().Add(entity);
            if (dbContext.SaveChanges() == 1) //1 change was made
                Items.Add(newEntity);
        }
        return newEntity;
    }

    public void Delete(TKey id)
    {
        using (TContext dbContext = new TContext())
        {
            var attachedEntry = dbContext.Set<T>().Find(id);
            if (attachedEntry == null) return; //it doesnt exist anyway!
            dbContext.Set<T>().Remove(attachedEntry);
            dbContext.SaveChanges();
            RefreshCache(dbContext);
        }
    }

    public void Update(T entity,TKey id)
    {
        if (entity == null) throw new ArgumentException("Cannot update a null entity.");

        using (TContext dbContext = new TContext())
        {
            var entry = dbContext.Entry(entity);

            if (entry.State != EntityState.Detached) return;
            T attachedEntity = dbContext.Set<T>().Find(id);

            if (attachedEntity != null)
            {
                var attachedEntry = dbContext.Entry(attachedEntity);
                attachedEntry.CurrentValues.SetValues(entity);
            }
            else
            {
                entry.State = EntityState.Modified; // This should attach entity
            }
            dbContext.SaveChanges();
            RefreshCache(dbContext);
        }
    }

    #region Transaction Methods
    public IUnitOfWork StartTransaction()
    {
        return new EFUnitOfWork(new TContext());
    }

    public T TransactionAdd(T entity,IUnitOfWork context)
    {
        context.Saved += OnSave;
        return context.Set<T>().Add(entity);
    }

    public void TransactionDelete(TKey id,IUnitOfWork context)
    {
        var attachedEntry = context.Set<T>().Find(id);
        if (attachedEntry == null) return; //it doesnt exist anyway
        context.Saved += OnSave;
        context.Set<T>().Remove(attachedEntry);
    }

    public void TransactionUpdate(T entity,TKey id,IUnitOfWork context)
    {
        if (entity == null) throw new ArgumentException("Cannot update a null entity.");

        var entry = context.Entry(entity);

        if (entry.State != EntityState.Detached) return;
        T attachedEntity = context.Set<T>().Find(id);

        if (attachedEntity != null)
        {
            var attachedEntry = context.Entry(attachedEntity);
            attachedEntry.CurrentValues.SetValues(entity);
        }
        else
        {
            entry.State = EntityState.Modified; // This should attach entity
        }
        context.Saved += OnSave;
    }

    private void OnSave(object sender,EventArgs e)
    {
        RefreshCache();
    }
    #endregion
}

它改编自网上的各种图案.我不认为这对于具有数十万行的表有用,但对于查找表等 – 我并不总是打到数据库.

它可以工作,但有些东西不是很干净,例如我刷新缓存 – 有时我必须再次拉取所有数据(目前正在进行中).

这个声音设计?还是我在这里重新发明轮子?

解决方法

一个有趣的问题1.在我看来,上下文内容缓存是最好的完成或单独保留的内容.并使用DB缓存.

为什么:

>并行WP都有缓存
>每个WP都可能有线程,上下文不是线程安全的
>每个线程都应该有缓存吗?
>您的缓存会话是否持久?

>否:您重新加载每个请求
>是:您在ASP.NET,EnterpriseLibary缓存或类似地方使用全局缓存?

>您是否正确管理缓存?
>你如何处理并发和变化

>您是否考虑过Context生命周期的最佳实践?一些专家建议只有短暂的寿命
> DB是否位于WebServer附近的LAN上?
>您是否比较了使用DB缓冲区访问时的响应时间?

在各种环境中研究了这个主题,而不仅仅是EF / .NET / SQL Server,我得出的结论是,除非DB服务器已经成为或者趋向于成为CPU瓶颈并且不能轻易扩展,否则它是一种非常合理的方法为DB提供内存并让它缓存100sMB
在构建或尝试缓存条目之前.
在使用WebServer上的app knots进行编码之前,我宁愿在SQL Server中抛出GB或RAM.

当每微秒计数时,或者您的数据库在网络范围内与延迟/吞吐量问题分离,并且您的数据是非易失性的,并且不需要缓存到期/并发管理.然后继续实施缓存.

仔细考虑内存使用,缓存构建时间和内存持久性模型.

查看一些用于缓存创意和潜在解决方案的工具.例如企业缓存块.

祝好运.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读