2016-07-26 21 views
0

Meine einfache Repository getAll Methode cachen:besserer Weg, um ein Modell

public List<ListModel> GetAllLists() 
    { 
      using (MySqlConnection connection = new MySqlConnection(this.connectionString)) 
      { 
       return connection.Query<ListModel>("SELECT * FROM projectx.lists").AsList(); 
      } 

    } 

Ich verwende diese Klasse die ich gefunden habe hier in so Caching zu handhaben:

public class CacheUtils : ICacheService 
    {  
     public TValue Get<TValue>(string cacheKey, Func<TValue> getItemCallback, double durationInMinutes = 120) where TValue : class 
     { 

      TValue item = MemoryCache.Default.Get(cacheKey) as TValue; 
      if (item == null) 
      { 
       Debug.WriteLine("Not cached"); 
       item = getItemCallback(); 
       MemoryCache.Default.Add(cacheKey, item, DateTime.Now.AddMinutes(durationInMinutes)); 
      } 
      else 
       Debug.WriteLine("Cached!"); 
      return item; 
     } 

     public TValue Get<TValue, TId>(string cacheKeyFormat, TId id, Func<TId, TValue> getItemCallback, double durationInMinutes = 120) where TValue : class 
     { 

      string cacheKey = string.Format(cacheKeyFormat, id); 
      TValue item = MemoryCache.Default.Get(cacheKey) as TValue; 
      if (item == null) 
      { 

       item = getItemCallback(id); 
       MemoryCache.Default.Add(cacheKey, item, DateTime.Now.AddMinutes(durationInMinutes)); 
      } 


      return item; 
     } 
    } 

Heimsteuerung:

public ActionResult Index() 
    { 
     ListRepository listRep = new ListRepository(); 
     CacheUtils cache = new CacheUtils(); 
     return View(cache.Get("lists", listRep.GetAllLists)); 
    } 

Frage, gibt es eine bessere Art und Weise Cache Handhabung als die hel Aufruf per von der Steuerung? Im Idealfall sollte es innerhalb der Repository-Methode sein. Aber muss ich die Überprüfung auf vorhandene Cache-Daten für jede einzelne Methode des Repositorys wiederholen? D. h .:

public List<ListModel> GetAllLists() 
    { 
     var lists = Cache["lists"]; 
     if(lists == null) 
     { 
      using (MySqlConnection connection = new MySqlConnection(this.connectionString)) 
      { 
       lists = connection.Query<ListModel>("SELECT * FROM projectx.lists").AsList(); 
      } 

      Cache["lists"] = lists; 
     } 
     return ((List<ListModel>)lists); 
    } 

Antwort

1

Verwenden Sie ein Decorator-Muster und polieren Sie nicht Geschäft oder UI mit Caching-Logik. Verbinden Sie es mit etwas wie Ninject (oder armen Bastarde, wenn Sie keine DI hinzufügen möchten) Ich würde empfehlen, es als einzelne Instanz zu markieren.

Vorteile:

  • eine Ungültigkeits Methode wie Leere Save (Listmodel) Hinzufügen einfach zu den Cache ungültig machen.
  • Ihre oberste Schicht und untere Schicht wissen nichts über die Tatsache, dass sie zwischengespeichert wurden.
  • Sie können auch wieder dekorieren in Protokollierung, Profilieren, etc
  • Sie können auch die Cache-Lebenszyklus steuern
  • Sie nicht verschmutzen die Controller-Ebene mit Caching-Logik
  • leicht zu entfernen
hinzufügen

So etwas wie das unten würde funktionieren. sehen, wie auch hinzufügen Dekorateure in ninject https://stackoverflow.com/a/8910599/1073280

public class MyHomeController 
{ 
    private readonly IListCrud _listcrud; 

    public MyHomeController(IListCrud listcrud) 
    { 
     _listcrud = listcrud; 
    } 

    public ActionResult Index() 
    { 
     return View(_listcrud.GetAllLists()); 
    } 
} 

public interface IListCrud 
{ 
    List<ListModel> GetAllLists(); 
} 

public class ListCrud : IListCrud 
{ 
    public List<ListModel> GetAllLists() 
    { 
     using (MySqlConnection connection = new MySqlConnection(this.connectionString)) 
     { 
      return connection.Query<ListModel>("SELECT * FROM projectx.lists").AsList(); 
     } 
    } 
} 

public class ListCrudCache : IListCrud 
{ 
    private readonly ICacheService _cache; 
    private readonly IListCrud _inner; 

    public ListCrudCache(ICacheService cache, IListCrud inner) 
    { 
     _cache = cache; 
     _inner = inner; 
    } 

    public List<ListModel> GetAllLists() 
    { 
     return _cache.Get("lists", _inner.GetAllLists); 
    } 
} 

Meinung: vielleicht nur den Code klein zu halten, aber seien Sie vorsichtig mit select * mit einem ORM. Wenn jemand eine Spalte umbenennt oder entfernt, haben Sie keinen einfachen Test-Fehler-Mechanismus.

0

Meiner Meinung nach sollte es nicht im Repository, da es (für mich) wie Verletzung oder SRP riecht. Caching sollte über dem Repository ein Service auf höherer Ebene sein.

Sie müssen darüber nachdenken, was die Vorteile des Caching tatsächlich benötigt. Wenn das Caching zur Beschleunigung der WEB-API-Schnittstelle dient, ist es bei weitem die beste Methode, sie in der Steuerung zu haben. Wenn Sie auch anderswo Caching benötigen, sollten Sie in Erwägung ziehen, einige Service-Klassen der mittleren Ebene einzuführen und Caching dort zu platzieren, aber ich würde es immer irgendwie optional machen.