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

Entity framework core .Net EF Core 2.1从IQueryable参数获取DbContext,entity-framework-core,asp.net-core-2.0,dbcontext,Entity Framework Core,Asp.net Core 2.0,Dbcontext,我有一个IQueryable扩展方法: public static void SomeExt<T>(this IQueryable<T> query, DbContext context) {...} publicstaticvoidsomext(这个IQueryable查询,DbContext上下文){…} 我想知道是否有某种方法可以从查询中获取DbContext,以便删除DbContext参数,只留下: public static void SomeExt<

我有一个IQueryable扩展方法:

public static void SomeExt<T>(this IQueryable<T> query, DbContext context) {...}
publicstaticvoidsomext(这个IQueryable查询,DbContext上下文){…}
我想知道是否有某种方法可以从查询中获取DbContext,以便删除DbContext参数,只留下:

public static void SomeExt<T>(this IQueryable<T> query) {...}
publicstaticvoidsomext(这个IQueryable查询){…}
我试过这样的东西 但它不起作用,没有字段

还有一种方法可以从DbSet获取它

myDbSet.GetService a.StatusId=1)

q.SomeExt(上下文)
vs

q.SomeExt()

听起来您想在实体框架中实现ActiveRecord。很多人都试过。。。我所能建议的最好方法是使您的上下文。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
}
公共类MyContext:DbContext
{
QueryableWithContext项{get=>new QueryableWithContext(ItemsSet,this)}
私有DbSet ItemsSet{get;set;}
}
公共类QueryableWithContext
{
公共DbContext上下文{get;}
私人易读内文;
公共QueryableWithContext(IQueryable内部,DbContext)
{
this.inner=内部;
this.Context=Context;
}
公共查询WithContext Where(Func谓词)
{
返回新的QueryableWithContext(inner.Where(谓词)作为IQueryable,Context);
}
//再加上许多其他类似LINQ的表达
}

然后您的扩展方法不是在
IQueryable
上,而是在
QueryableWithContext
上,并且可以访问
Context
属性。

我找到了一种方法来实现这一点

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;

    return stateManager.Context;
}
对于EFCore 3,而不是

.GetProperty("Dependencies", bindingFlags)
使用

试试这个

 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;
    }
publicstaticdbcontext GetDbContext(此IQueryable查询)
{
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(编译器);
对象状态管理动态;
var dependenciesProperty=typeof(RelationalQueryContextFactory).GetProperty(“依赖项”,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(依赖项);
}
其他的
{
//efcore1.x
var stateManagerField=typeof(QueryContextFactory).GetProperty(“StateManager”,BindingFlags.NonPublic | BindingFlags.Instance);
stateManagerDynamic=stateManagerField.GetValue(queryContextFactory);
}
IStateManager stateManager=stateManager动态作为IStateManager;
if(stateManager==null)
{
Microsoft.EntityFrameworkCore.Internal.LazyRef lazyStateManager=stateManagerDynamic作为Microsoft.EntityFrameworkCore.Internal.LazyRef;
if(lazyStateManager!=null)
{
stateManager=lazyStateManager.Value;
}
}
if(stateManager==null)
{
stateManager=((动态)stateManagerDynamic).Value;
}
返回stateManager.Context;
}

这不适用于任何IQueryable实现,因此我们必须依赖底层类型。对于要在其上使用的IQueryable,
query.GetType().FullName
的值是什么?对于此查询类型(即“项”)的全名,我得到:“Microsoft.EntityFrameworkCore.query.Internal.EntityQueryable`1[[EFCore.MyExtensions.Tests.Item,EFCore.MyExtensions.Tests,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null]]”这是一件非常奇怪的事情,也许您可以解释一下为什么需要它?对于BatchDelete作为查询扩展。您遇到的问题与我目前面临的问题完全相同!那么,您最终是否决定将上下文作为参数传递,或者下面的解决方案之一是否适合您?我不想将上下文与IQueryable捆绑在一起,但我也不太热衷于一个每次更新EFCore时都会中断的解决方案……这主意不错,但要求每个集合都有单独的QueryableWithContext,所以这并不理想。我可能会坚持以发送上下文作为参数。是的,我建议我昨天就这么做了,哈哈,但是在我的代码库中处于最高抽象级别。我有一个根数据库项目,每个实体都实现了IEntity,所以我创建了一个类ContextQueryable:IQueryable,其中T:IEntity。获取此类实例的唯一方法是在构造函数中传入IQueryable和Database.Context。我这样做是因为我有一些扩展方法需要执行子查询,但我怀疑这是否意味着扩展方法是一个糟糕的设计选择。但可能不是这样,因为可能只有我的派生db项目可以使用它们……小心!虽然这是可行的,但它依赖于内部私有属性,这些属性在每次更新EFCore时都可能发生更改。即使是补丁版本也可能会破坏这一点。
 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;
    }