2013-07-19 49 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 
} 
} 
相關問題