我有一个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();
答案 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;
}