簡體   English   中英

在 Asp.Net Core + EF Core 中緩存數據的模式?

[英]Pattern for caching data in Asp.Net Core + EF Core?

我有一個 Asp.Net Core + EF Core REST 服務。 我為要調用 SP 的數據庫創建了一個 DbContext 類。 該方法幾乎如下所示:

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

這一切都有效,但是每次都調用 SP 沒有任何意義,因為 SP 返回的數據很少發生變化。 我想讓數據過時,比如每 24 小時一次。

在 Core 中這樣做是否有首選模式? 我看到他們有 .AddCaching 擴展方法,但這似乎會被注入到控制器中? 那么它的控制器工作要緩存嗎? 我假設它是線程安全的,所以我不需要做任何鎖定或類似的事情? 似乎是一種競爭條件,如果一個線程正在檢查該項目是否已加載到緩存中,另一個線程可能正在插入它,等等?

好吧,您可以應用裝飾器模式 它不是特定於 .NET Core 的,只是一種常見模式。

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 = repository.GetModel();

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

        return value;
    }
}

由於 ASP.NET Core DI 不支持攔截器或裝飾器,因此您的 DI 注冊將變得更加冗長。 或者使用支持裝飾器注冊的 3rd 方 IoC 容器。

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

這樣做的好處是您可以清楚地分離關注點,並且可以通過將 DI 配置更改為

services.AddScoped<IMyRepository,MyRepository>();

你可以使用這個第三方包: https : //github.com/VahidN/EFSecondLevelCache.Core

使用 AspNetCore MW 和 EfCore 擴展(可緩存),如下所示:

var posts = context.Posts
                   .Where(x => x.Id > 0)
                   .OrderBy(x => x.Id)
                   .Cacheable()
                   .ProjectTo<PostDto>(configuration: _mapper.ConfigurationProvider)
                   .ToList();

ProjectTo<>() 是 AutoMapper 擴展。

有一個二級緩存擴展可以做你想做的事。 它被稱為EntityFrameworkCore.Cacheable (是的,它是由我創建的,因為我遇到了類似的問題)。

這里有一個基於擴展使用的示例:

var cacheableQuery = cacheableContext.Books
    .FromSql("pr_Getxxx")
    .Cacheable(TimeSpan.FromHours(24));

Cacheable(...方法調用將第一個結果存儲到內存緩存中,如果再次調用相同的 linq 表達式,則返回緩存的結果 24 小時。

您可以使用 ASP.Net Core Memory Cache 來緩存數據。 然后您可以根據需要設置滑動/絕對到期時間。 參考 MemoryCahe 的文檔https://docs.microsoft.com/en-us/aspnet/core/performance/caching/memory?view=aspnetcore-5.0

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM