C# EntityFramework核心缓存数据在内存中保持异步操作

C# EntityFramework核心缓存数据在内存中保持异步操作,c#,.net-core,entity-framework-core,ef-core-3.0,C#,.net Core,Entity Framework Core,Ef Core 3.0,我有一个使用EF Core 3.0的工作应用程序(现在预览8)。有一个数据集很少更改,但查询非常频繁。实际对数据执行操作的服务通过一个非常简单的接口进行隔离 interface IDataProvider { ValueTask<IQueryable<DataRow>> GetDataAsync(); } 听起来不错,但不起作用-服务实现在IQueryable上广泛使用异步操作,因此toListSync(),AnyAsync()等。在缓存的列表上调用其中任何一个

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

interface IDataProvider
{
    ValueTask<IQueryable<DataRow>> GetDataAsync();
}
听起来不错,但不起作用-服务实现在
IQueryable
上广泛使用异步操作,因此
toListSync()
AnyAsync()
等。在缓存的
列表上调用其中任何一个将导致EF Core抛出
InvalidOperationException
,并显示消息
只有实现IAsyncEnumerable的源才能用于实体框架异步操作。

这个错误很常见,因为对服务进行单元测试时也会抛出同样的错误。在那里,我模拟了一个
IAsyncQueryProvider
实现(呼喊),所以在这里我可以做同样的事情

或者,我可以为
ToListAsync
AnyAsync
等编写自己的扩展方法,并实现

public static Task<List<T>> ToListAsync<T>(this IQueryable<T> queryable)
{
    if(queryable is IAsyncEnumerable<T>)
    {
        return Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync(queryable);
    }

    return Task.FromResult(queryable.ToList());
}
公共静态任务ToListSync(此IQueryable可查询)
{
if(queryable是IAsyncEnumerable)
{
返回Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListSync(queryable);
}
返回Task.FromResult(queryable.ToList());
}

这两种方法都需要大量的工作和测试来完成如此简单的事情。是否有更可靠的解决方案?或者我把我的服务与EntityFrameworkQueryableExtensions捆绑在一起,把自己逼到了墙角,我无法透明地使用内存中的提供程序。

是的,看起来像是一个泄漏的抽象。我可能同意你对EF紧耦合问题的评估。看看下面的EF核心扩展-是的,看起来像一个泄漏的抽象。我可能同意您对EF问题紧密耦合的评估-
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;
    }
}
public static Task<List<T>> ToListAsync<T>(this IQueryable<T> queryable)
{
    if(queryable is IAsyncEnumerable<T>)
    {
        return Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync(queryable);
    }

    return Task.FromResult(queryable.ToList());
}