Расширение метода EF Core - PullRequest
0 голосов
/ 17 апреля 2020

То, чего я пытаюсь добиться, - это создать метод расширения для 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, но сдался. Если кто-нибудь знает, как это сделать, я бы купил пару напитков.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...