2016-11-14 1 views
2

Ich habe einen Asp.Net Core + EF Core REST-Dienst. Ich habe eine DbContext-Klasse für eine DB erstellt, die ich SP aufrufen möchte. Das Verfahren ziemlich sieht aus wie:Muster zum Zwischenspeichern von Daten in Asp.Net Core + EF Core?

public IQueryable<xxx> Getxxxs() 
{ 
    return Set<xxx>().FromSql("pr_Getxxx"); 
} 

das alles funktioniert, aber es gibt keinen Punkt, um die SP jedes Mal in Aufruf, da die Daten nur selten ändert sich die SP kehrt zurück. Ich möchte die Daten veralten lassen, sagen wir alle 24 Stunden.

Gibt es ein bevorzugtes Muster dafür in Core? Ich sehe, sie haben die. AddCaching-Erweiterung-Methode, aber das scheint, als würde es in den Controller injiziert werden? Also ist es der Controller Job zu cachen? Ich gehe davon aus, dass es threadsicher ist, also muss ich keine Verriegelung oder ähnliches machen? Scheint es wie eine Race-Bedingung, wenn ein Thread prüft, ob das Element in den Cache geladen wurde, das andere es möglicherweise einfügt usw.?

+3

verändern Sie können ** BITTE ** stoppen sie EF7 anrufen. Dieser Name wird nicht offiziell für 6 Monate verwendet. Es heißt EntityFramework Core und ist als 1.0 versioniert, um zu verdeutlichen, dass es nicht die nächste Version von EF6 ist. Bitte beachten Sie diese Ankündigung hier http://www.hanselman.com/blog/ASPNET5IsDeadIntroducingASPNETCore10AndNETCore10.aspx – Tseng

+0

Wird dieser Service dauerhaft ausgeführt oder nur ausgeführt, wenn aufgerufen und danach beendet? Sie müssen irgendwie das Ergebnis und den Zeitstempel der Zeit zwischenspeichern, als Sie zuletzt auf die Daten aus der Datenbank zugegriffen haben. Die Datenbank sollte jedoch viel von diesem Caching-Zeug selbst erledigen. –

+0

@ThomasRoskop, der Dienst läuft immer. Die Funktionsweise von Core, der Controller und der Kontext werden bei jedem Aufruf neu definiert. Sie haben den MemoryCache, der nach X Zeit ablaufen kann. Es scheint nur für eine Race-Bedingung offen. – SledgeHammer

Antwort

1

Nun, Sie können die decorator pattern anwenden. Es ist nichts .NET Core-spezifisch, nur ein übliches Muster.

public class MyModel 
{ 
    public string SomeValue { get; set; } 
} 

public interface IMyRepository 
{ 
    IEnumerable<MyModel> GetModel(); 
} 

public class MyRepository : IMyRepository 
{ 
    public IEnumerable<MyModel> GetModel() 
    { 
     return Set<MyModel>().FromSql("pr_GetMyModel"); 
    } 
} 

public class CachedMyRepositoryDecorator : IMyRepository 
{ 
    private readonly IMyRepository repository; 
    private readonly IMemoryCache cache; 
    private const string MyModelCacheKey = "myModelCacheKey"; 
    private MemoryCacheEntryOptions cacheOptions; 

    // alternatively use IDistributedCache if you use redis and multiple services 
    public CachedMyRepositoryDecorator(IMyRepository repository, IMemoryCache cache) 
    { 
     this.repository = repository; 
     this.cache = cache; 

     // 1 day caching 
     cacheOptions = new MemoryCacheEntryOptions() 
      .SetAbsoluteExpiration(relative: TimeSpan.FromDays(1)); 
    } 

    public IEnumerable<MyModel> GetModel() 
    { 
     // Check cache 
     var value = cache.Get<IEnumerable<MyModel>>("myModelCacheKey"); 
     if(value==null) 
     { 
      // Not found, get from DB 
      value = Set<MyModel>().FromSql("pr_GetMyModel").ToArray(); 

      // write it to the cache 
      cache.Set("myModelCacheKey", value, cacheOptions); 
     } 

     return value; 
    } 
} 

Da die ASP.NET Core-DI, wird Ihre DI Registrierung etwas ausführlicher nicht Abfangjäger oder Dekorateure unterstützt werden. Alternativ können Sie einen IoC-Container eines Drittanbieters verwenden, der Decorator-Registrierungen unterstützt.

services.AddScoped<MyRepository>(); 
services.AddScoped<IMyRepository, CachedMyRepositoryDecorator>(
    provider => new CachedMyRepositoryDecorator(
     provider.GetService<MyRepository>(), 
     provider.GetService<IMemoryCache>() 
    )); 

Dies hat den Vorteil, dass Sie eine klare Trennung von Bedenken haben und das Caching leicht deaktivieren können durch die DI-Konfiguration

services.AddScoped<IMyRepository,MyRepository>();