2011-04-25 75 views
11

我开始在ASP.NET MVC网站的缓存基础结构上工作。问题是,我似乎无法找到数据缓存一个合理的地方(除“无处不在”)ASP.NET存储库模式/服务层缓存

现在我的建筑看起来像这样:

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

该存储库公开了像Insert,GetById和GetQueryable这样的通用方法,该方法返回服务层可以进一步优化的IQueryable。

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

假设我们有一个用户表和一个订单表(规范示例)。服务层提供像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到任何服务层都不知道底层源)。

+1

看起来像一个正确的缓存评估和它的危险。 – gt124 2011-04-25 17:56:24

+0

查看此答案:https://stackoverflow.com/a/7805942/13729 – ssmith 2017-11-20 02:06:36

回答

8

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

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

+1

感谢您的回复。我认为这是我要采取的方法。我已经阅读了大量试图在存储库层保持缓存的文章,但我认为这个解决方案最有意义。 – mfanto 2011-04-25 20:14:55

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的建议,并把缓存失效逻辑放在一个单独的服务。您不需要创建一个单独的“数据缓存层”,但如果保存在不同的类中,则逻辑将更清晰。

+0

感谢您的回复。我想现在我要去ventaur(和你)建议的路线,一旦我可以迁移到像EF这样的东西,重新评估缓存选项。我喜欢订阅更改通知的想法。部分应用程序分布在多个服务中,这可以帮助立即使陈旧的数据无效。 – mfanto 2011-04-25 20:18:12