EntityFramework Core内存中的缓存数据保持异步操作

时间:2019-08-29 13:23:05

标签: c# .net-core entity-framework-core ef-core-3.0

我有一个正在使用EF Core 3.0的应用程序(目前预览8)。有一个数据集很少更改,但查询非常频繁。实际执行数据操作的服务是通过一个非常简单的界面隔离的。

interface IDataProvider
{
    ValueTask<IQueryable<DataRow>> GetDataAsync();
}

到目前为止,只有一个基于实际SQL数据库的数据提供程序实现。因此,如果我们有一个DbSet<DataRow> Data的DbContext:

class LiveDataProvider : IDataProvider
{
    private readonly DataDbContext _dbContext;

    public LiveDataProvider(DataDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public ValueTask<IQueryable<DataRow>> GetDataAsync() => 
        new ValueTask<IQueryable<DataRow>>(_dbContext.Data.AsNoTracking());
}

现在,我负责向该应用程序添加缓存。因此,我们的想法是将整个Data集存储在内存中,因为在数据库上进行检索是相当昂贵的查询,但是数据量仅为几百MB。由于很少进行更新,因此绝大多数请求都会到达缓存。有了这个想法,实现似乎就很简单了:

class InMemoryDataCache : IDataProvider
{
    private readonly IPicksDbContext _picksDbContext;
    private readonly IMemoryCache _memoryCache;

    public async ValueTask<IQueryable<DataRow>> GetDataAsync()
    {
        var entryKey = GetEntryKey(); // Implementation is irrelevant.

        if (!_memoryCache.TryGetValue(entryKey, out IQueryable<DataRow> data))
        {
            data = (await _dbContext.Data.AsNoTracking().ToListAsync()).AsQueryable();
            _memoryCache.Set(entryKey, data);
        }

        return data;
    }

    InMemoryDataCache(DataDbContext dbContext, IMemoryCache memoryCache)
    {
        _dbContext = dbContext;
        _memoryCache = memoryCache;
    }
}

听起来不错,没用-服务实现广泛使用IQueryable上的异步操作,因此ToListAsync()AnyAsync()等。在已缓存的{{1 }}将导致EF Core抛出List和消息InvalidOperationException

该错误非常熟悉,因为对服务进行单元测试也引发了同样的事情。在那里,我模拟了Only sources that implement IAsyncEnumerable can be used for Entity Framework asynchronous operations.的实现(对MockQueryable的喊叫),所以在这里我可以做同样的事情。

或者,我可以使用{p>的实现为IAsyncQueryProviderToListAsync等编写自己的扩展方法

AnyAsync

对于如此简单的事情,两者都需要大量的工作和测试。有没有更强大的解决方案?还是我首先将服务与EntityFrameworkQueryableExtensions绑定在一起而陷入困境,而我无法透明地使用内存提供程序。

0 个答案:

没有答案