.Net EF Core 2.1从IQueryable参数获取DbContext

时间:2018-11-07 21:49:53

标签: entity-framework-core asp.net-core-2.0 dbcontext

我有一个IQueryable扩展方法:

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

,我想知道是否有某种方法可以从查询中获取DbContext,以便可以删除DbContext参数,而只留下:

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

我尝试过这样的事情 Access DataContext behind IQueryable 但它不起作用,得到零字段。

还有一种方法可以从DbSet中获取它
Can you get the DbContext from a DbSet?
myDbSet.GetService <'ICurrentDbContext>()。Context;
但这不是我所需要的。我想从查询中获取它吗?

这是查询:
var q = context.Items.Where(a => a.StatusId = 1);

q.SomeExt(context);
vs
q.SomeExt();

3 个答案:

答案 0 :(得分:1)

您想要在Entity Framework中实现ActiveRecord的声音。许多人都尝试过...最好的建议是使您的context.Items属性成为类似于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属性。

答案 1 :(得分:0)

我找到了一种方法

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;
}

答案 2 :(得分:0)

尝试

 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;
    }