.Net EF Core 2.1 Получить аргумент DbContext из аргумента IQueryable - PullRequest
0 голосов
/ 08 ноября 2018

У меня есть метод расширения IQueryable:

public static void SomeExt<T>(this IQueryable<T> query, DbContext context) {...}

и я хотел бы знать, есть ли какой-нибудь способ получить DbContext из запроса, чтобы можно было удалить аргумент DbContext, оставив только:

public static void SomeExt<T>(this IQueryable<T> query) {...}

Я пробовал что-то подобное Доступ к DataContext за IQueryable но это не работает, получая ноль полей.

Также есть способ получить его из DbSet
Можете ли вы получить DbContext из DbSet?
myDbSet.GetService < 'ICurrentDbContext> () контекст;.
но это не то, что мне нужно. Я хочу получить его из запроса?

Это запрос:
var q = context.Items.Where (a => a.StatusId = 1);

q.SomeExt (контекст);
против
q.SomeExt ();

Ответы [ 3 ]

0 голосов
/ 16 ноября 2018

Я нашел способ сделать это

public static DbContext GetDbContext(IQueryable query)
{
    var bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
    var queryCompiler = typeof(EntityQueryProvider).GetField("_queryCompiler", bindingFlags).GetValue(query.Provider);
    var queryContextFactory = queryCompiler.GetType().GetField("_queryContextFactory", bindingFlags).GetValue(queryCompiler);

    var dependencies = typeof(RelationalQueryContextFactory).GetProperty("Dependencies", bindingFlags).GetValue(queryContextFactory);
    var queryContextDependencies = typeof(DbContext).Assembly.GetType(typeof(QueryContextDependencies).FullName);
    var stateManagerProperty = queryContextDependencies.GetProperty("StateManager", bindingFlags | BindingFlags.Public).GetValue(dependencies);
    var stateManager = (IStateManager)stateManagerProperty;
    stateManager = stateManager ?? (((LazyRef<IStateManager>)stateManagerProperty)?.Value ?? ((dynamic)stateManagerProperty).Value);

    return stateManager.Context;
}
0 голосов
/ 22 декабря 2018

попробуйте

 public static DbContext GetDbContext(this IQueryable query)
    {
        var compilerField = typeof(EntityQueryProvider).GetField("_queryCompiler", BindingFlags.NonPublic | BindingFlags.Instance);
        var compiler = (QueryCompiler)compilerField.GetValue(query.Provider);

        var queryContextFactoryField = compiler.GetType().GetField("_queryContextFactory", BindingFlags.NonPublic | BindingFlags.Instance);
        var queryContextFactory = (RelationalQueryContextFactory)queryContextFactoryField.GetValue(compiler);


        object stateManagerDynamic;

        var dependenciesProperty = typeof(RelationalQueryContextFactory).GetProperty("Dependencies", BindingFlags.NonPublic | BindingFlags.Instance);
        if (dependenciesProperty != null)
        {
            // EFCore 2.x
            var dependencies = dependenciesProperty.GetValue(queryContextFactory);

            var stateManagerField = typeof(DbContext).GetTypeFromAssembly_Core("Microsoft.EntityFrameworkCore.Query.QueryContextDependencies").GetProperty("StateManager", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
            stateManagerDynamic = stateManagerField.GetValue(dependencies);
        }
        else
        {
            // EFCore 1.x
            var stateManagerField = typeof(QueryContextFactory).GetProperty("StateManager", BindingFlags.NonPublic | BindingFlags.Instance);
            stateManagerDynamic = stateManagerField.GetValue(queryContextFactory);
        }

        IStateManager stateManager = stateManagerDynamic as IStateManager;

        if (stateManager == null)
        {
            Microsoft.EntityFrameworkCore.Internal.LazyRef<IStateManager> lazyStateManager = stateManagerDynamic as Microsoft.EntityFrameworkCore.Internal.LazyRef<IStateManager>;
            if (lazyStateManager != null)
            {
                stateManager = lazyStateManager.Value;
            }
        }

        if (stateManager == null)
        {
            stateManager = ((dynamic)stateManagerDynamic).Value;
        }


        return stateManager.Context;
    }
0 голосов
/ 08 ноября 2018

Звучит так, будто вы хотите реализовать ActiveRecord в Entity Framework. Многие пытались ... Лучшее, что я могу предложить, это сделать ваш контекст. Свойство элементов чем-то похожим на LINQ, которое запускает контекст, например:

public class MyContext : DbContext
{
    QueryableWithContext<Item> Items {get => new QueryableWithContext<Item>(ItemsSet, this)}
    private DbSet<Item> ItemsSet {get;set;}
}

public class QueryableWithContext<T>
{
    public DbContext Context { get; }
    private IQueryable<T> inner;

    public QueryableWithContext(IQueryable<T> inner, DbContext context)
    {
        this.inner = inner;
        this.Context = context;
    }

    public QueryableWithContext<T> Where(Func<T,bool> predicate)
    {
        return new QueryableWithContext<T>(inner.Where(predicate) as IQueryable<T>, Context);
    }

    // plus lots of other LINQ-like expressions
}

Тогда ваш метод расширения не на IQueryable<T>, а на QueryableWithContext<T> и может получить доступ к свойству Context.

...