ASP.NET存储库模式/服务层缓存

时间:2011-04-25 17:38:41

标签: asp.net caching repository-pattern

我开始研究ASP.NET MVC站点的缓存基础架构。问题是,我似乎找不到合理的数据缓存位置(除了“无处不在”)

现在我的架构看起来像这样:

控制器 - >服务层 - >库。存储库使用Linq to SQL进行数据访问。

存储库公开了一些通用方法,如Insert,GetById和GetQueryable,它们返回服务层可以进一步细化的IQueryable。

我喜欢将缓存放在存储库层中的想法,因为服务层不应该真正关心数据来自何处。但问题是缓存失效。服务层有关于数据何时变得陈旧而不是存储库的更多信息。例如:

假设我们有一个Users表和一个Orders表(规范示例)。服务层提供了GetOrder(int id)等方法,它们可以调用存储库层:

public Order GetOrder(int id)
{
    using(var repo = _repoFactory.Create<Order>())
    {
        return repo.GetById(id)
    }
}

repo.GetQueryable(order => order.Id == id && order.HasShipped == false).Single();

如果我们在存储库层中进行缓存,那么在知道订单数据何时发生变化时,它似乎非常有限。假设用户已被删除,导致所有订单都被CASCADE删除。服务层可能使Orders缓存无效,因为它知道用户刚被删除。虽然存储库(因为它是工作单元),但是不知道。 (忽略我们不应该查询已删除用户的订单这一事实,因为它只是一个例子)。

在其他情况下,我认为这表明了这一点。假设我们想要获取所有用户订单:

repo.GetQueryable(order => order.UserId == userId).ToList()

存储库可以缓存此查询的结果,但是,如果添加了另一个订单,则此查询不再有效。但是只有服务层才知道这一点。

我对存储库层的理解也是错误的。我把它视为围绕数据源的外观(即从L2SQL更改为EF到任何东西,服务层不知道底层源)。

2 个答案:

答案 0 :(得分:8)

实际上,你需要另一层;数据缓存层。请求数据时,服务层将使用它。根据这样的请求,它将决定它是否具有缓存中的数据,或者是否需要查询相应的存储库。同样,您的服务层可以告知此新数据缓存层失效(删除特定用户等)。

这对您的架构意味着什么,是您的数据缓存层将实现您的存储库所执行的相同接口。一个相当简单的实现将按实体类型和密钥缓存数据。但是,如果你在幕后使用更复杂的ORM(NHibernate,EF 4等),它应该有缓存作为你的选择。

答案 1 :(得分:2)

您可以在存储库返回的对象上放置一个事件,并让存储库将缓存失效订阅到处理程序。

例如,

  public class SomethingRepository{
        public Something GetById(int id){
            var something = _table.Single(x=>x.id==id);
            something.DataChanged += this.InvalidateCache;
            return something;
        }

        public void InvalidateCache(object sender, EventArgs e){ 
            // invalidate your cache 
        }
  }

您的Something对象需要有DataChanged个事件和一些公共方法供服务层调用才能触发它。像,

  public class Something{
       private int _id;
       public int Id{
         get { return _id; }
         set {
            if( _id != value ) 
            {
              _id = value;
              OnDataChanged();
            }
         }
       }
       public event EventHandler DataChanged;
       public void OnDataChanged(){
            if(DataChanged!=null)
                 DataChanged(this, EventArgs.Empty);
       }
  } 

因此,您的所有服务层需要知道的是数据正在被更改,并且存储库处理缓存失效。

我还建议您接受Ventaur的建议,并将缓存失效逻辑放在单独的服务中。您不需要创建单独的“数据缓存层”,但如果保存在不同的类中,逻辑将更清晰。