То, чего я пытаюсь добиться, - это создать метод расширения для EFCore, чтобы ввести простой проверочный кэш памяти, сначала подход. Мой производный класс DbContext выглядит следующим образом:
public partial class MyContext : DbContext
{
internal readonly IMemoryCache _cache;
private readonly IDistributedCache _cacheDistributed;
public MyContext ()
{
}
public MyContext (DbContextOptions<MyContext> options, IMemoryCache memoryCache, IDistributedCache cache)
: base(options)
{
_cache = memoryCache;
_cacheDistributed = cache;
}
...
blah blah blah
...
}
Я использую Dependency Injection для прохождения кеша памяти и распределенного кеша, который я хотел бы использовать в моем методе расширения, как показано ниже:
public static class EFCoreExtensions
{
internal static IQueryable<TEntity> FromSqlOnQueryable<TEntity>(
[NotNull] this IQueryable<TEntity> source,
[NotParameterized] string sql,
[NotNull] params object[] parameters)
where TEntity : class
=> throw new NotImplementedException();
internal static readonly MethodInfo FromSqlOnQueryableMethodInfo
= typeof(RelationalQueryableExtensions)
.GetTypeInfo().GetDeclaredMethods(nameof(FromSqlOnQueryable))
.Single();
//[StringFormatMethod("sql")]
public static async Task<List<TEntity>> CachedListFromSqlRawAsync<TEntity>(
[NotNull] this DbSet<TEntity> source,
//Microsoft.Extensions.Caching.Memory.IMemoryCache _cache,
[NotNull] [NotParameterized] string sql,
[NotNull] params object[] parameters)
where TEntity : class
{
//var infrastructure = source as Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure<IServiceProvider>;
//var serviceProvider = infrastructure.Instance;
//var currentDbContext = serviceProvider.GetService(typeof(MyContext)) as MyContext;
//var _cache = currentDbContext._cache;
var context = source.GetService<ICurrentDbContext>().Context as MyContext;
var _cache = context._cache;
string cache_key = String.Concat(sql, String.Join("-", from o in parameters select (o is null ? "!" : o).ToString()));
var ret = await _cache.GetOrCreate(cache_key, async entry => {
entry.AbsoluteExpiration = DateTime.Now.AddMinutes(60);
var queryableSource = (IQueryable)source;
var ret = await queryableSource.Provider.CreateQuery<TEntity>(
Expression.Call(
null,
FromSqlOnQueryableMethodInfo.MakeGenericMethod(typeof(TEntity)),
queryableSource.Expression,
Expression.Constant(sql),
Expression.Constant(parameters))).ToListAsync();
return ret;
});
return ret;
}
}
Но это не работает context._cache имеет значение null
Я могу передать кэш в качестве параметра методу, но это не выглядит как очень элегантное решение.
Кто-нибудь знает, как это сделать?
Я также изначально играл с идеей вернуть IQueryable вместо List, но сдался. Если кто-нибудь знает, как это сделать, я бы купил пару напитков.