2013-07-19 51 views
1

我有一个存储库,例如UserRepository。它通过给定的userId返回一个用户。我在Web应用程序上工作,所以对象被加载到内存中,在请求结束时使用和处理。对于存储库模式,我应该首先检查查询的对象是否存在于内存中,然后再进行实际的数据库调用

到目前为止,当我编写存储库时,我只是从数据库中检索数据。我不会将检索到的User对象存储到内存中(我的意思是在存储库的集合中)。当调用版本库的GetById()方法时,我不检查对象是否已经在集合中。我只是查询数据库。

我的问题是

  1. 我应该存储在存储器中检索对象,当仓库中的get方法被调用时,我应该检查对象存在于内存我做任何数据库调用的第一过吗?
  2. 或者是内存收集不必要的,因为web请求是一个短暂的会议,所有的物品设置之后

回答

3

1)我应该检索对象存储在存储器中,当仓库中的Get方法被调用时,我应该在进行任何数据库调用之前检查对象是否存在于内存中?

由于您的存储库应该足够抽象以模拟内存集合的目的,我认为这真的取决于您和您的使用案例。

如果您在从数据库中检索到对象后存储对象,则最终可能会执行所谓的IdentityMap。如果你这样做,它会变得非常复杂(这取决于你的域名)。

根据您所依赖的基础架构层,您可以使用ORM提供的IdentityMap(如果有)。

但真正的问题是,值得实施一个IdentityMap吗?

我的意思是,我们同意,重复的查询可能有两个原因,性能和完整性,在这里马丁·福勒的报价是错误的:

一个古老的谚语说,有两个手表的人从来不知道什么它是时间。如果两个手表令人困惑,那么从数据库加载对象可能会导致更大的混乱。

但有时你需要务实,只需在每次需要时加载它们。

2)或者是内存收集不必要的,因为web请求是一个短暂的会议,所有的物品设置之后

这取决于™,例如,在某些情况下,你可能要在不同的地方玩你的对象,在这种情况下,这可能是值得的,但是假设你需要通过从数据库加载你的用户来刷新你的用户会话身份,那么在有些情况下你只能在整个请求中执行一次。

+0

+1和想补充一点, ORM中的身份映射存在于Web应用程序对应于单个请求的工作单元的持续时间内。因此,在这种情况下,显式标识映射似乎是不必要的。 – eulerfx

1

正如通常情况下,我不认为会有“一刀切”。

有可能是其中一个可以实现缓存的形式存储库时的数据往往是检索,不走过时太快,或者仅仅出于效率的情况。

但是,您可以很好地实现一种通用缓存修饰器,可以在需要时包装存储库。

所以应该把每个用例作为优点。

1

当你使用像实体框架或NHibernate这样的ORM时,它已经被处理了 - 所有读取的实体都通过IdentityMap机制进行跟踪,通过键搜索(EF中的DbSet.Find)甚至不会击中数据库实体已经加载。

如果您使用直接访问数据库或microORM作为基础信息库,你要小心 - 不IdentityMap你基本上与值对象的工作:

using System; 
using System.Collections.Generic; 
using System.Linq; 

namespace test 
{ 
internal class Program 
{ 
    static void Main() 
    { 
     Console.WriteLine("Identity map"); 
     var artrepo1 = new ArticleIMRepository(); 
     var o1 = new Order(); 
     o1.OrderLines.Add(new OrderLine {Article = artrepo1.GetById(1, "a1", 100), Quantity = 50}); 
     o1.OrderLines.Add(new OrderLine {Article = artrepo1.GetById(1, "a1", 100), Quantity = 30}); 
     o1.OrderLines.Add(new OrderLine {Article = artrepo1.GetById(2, "a2", 100), Quantity = 20}); 
     o1.ConfirmOrder(); 
     o1.PrintChangedStock(); 
     /* 
     Art. 1/a1, Stock: 20 
     Art. 2/a2, Stock: 80 
     */ 

     Console.WriteLine("Value objects"); 
     var artrepo2 = new ArticleVORepository(); 
     var o2 = new Order(); 
     o2.OrderLines.Add(new OrderLine {Article = artrepo2.GetById(1, "a1", 100), Quantity = 50}); 
     o2.OrderLines.Add(new OrderLine {Article = artrepo2.GetById(1, "a1", 100), Quantity = 30}); 
     o2.OrderLines.Add(new OrderLine {Article = artrepo2.GetById(2, "a2", 100), Quantity = 20}); 
     o2.ConfirmOrder(); 
     o2.PrintChangedStock(); 
     /* 
     Art. 1/a1, Stock: 50 
     Art. 1/a1, Stock: 70 
     Art. 2/a2, Stock: 80 
     */ 
     Console.ReadLine(); 
    } 
    #region "Domain Model" 
    public class Order 
    { 
     public List<OrderLine> OrderLines = new List<OrderLine>(); 

     public void ConfirmOrder() 
     { 
      foreach (OrderLine line in OrderLines) 
      { 
       line.Article.Stock -= line.Quantity; 
      } 
     } 

     public void PrintChangedStock() 
     { 
      foreach (var a in OrderLines.Select(x => x.Article).Distinct()) 
      { 
       Console.WriteLine("Art. {0}/{1}, Stock: {2}", a.Id, a.Name, a.Stock); 
      } 
     } 
    } 

    public class OrderLine 
    { 
     public Article Article; 
     public int Quantity; 
    } 

    public class Article 
    { 
     public int Id; 
     public string Name; 
     public int Stock; 
    } 
    #endregion 

    #region Repositories 
    public class ArticleIMRepository 
    { 
     private static readonly Dictionary<int, Article> Articles = new Dictionary<int, Article>(); 

     public Article GetById(int id, string name, int stock) 
     { 
      if (!Articles.ContainsKey(id)) 
       Articles.Add(id, new Article {Id = id, Name = name, Stock = stock}); 
      return Articles[id]; 
     } 
    } 

    public class ArticleVORepository 
    { 
     public Article GetById(int id, string name, int stock) 
     { 
      return new Article {Id = id, Name = name, Stock = stock}; 
     } 
    } 
    #endregion 
} 
} 
相关问题