【问题标题】:Get IQueryProvider from DbContext从 DbContext 获取 IQueryProvider
【发布时间】:2016-07-25 08:19:56
【问题描述】:

我正在尝试编写一个查询提供程序,它在执行前实例化 DbContext,执行查询,然后立即释放生成的上下文对象。

为此,我必须实现IQueryProvider.Execute(....)。在这个方法中,我需要从我的DbContext 对象中获取IQueryProvider 以让它执行查询。

问题是我不知道如何从上下文对象访问提供者。据我所知,它存储在((IObjectContextAdapter)context).ObjectContext.QueryProvider,但该属性是内部的。

我也尝试从 DbSet 中获取它,但我不知道要指定什么类型。 context.Set(type?).AsQueryable().Provider.Execute<TResult>(expression)context.Set<type?>().AsQueryable().Provider.Execute<TResult>(expression)

所以我的问题是如何从给定的DbContext 对象中获取底层的IQueryProvider

我要解决的根本问题

我想在不同的上下文中针对同一个数据库执行多个查询。但是 DbContext 是 IDisposable 你必须将它包装在 using.Blocks 中。

IEnumerable<T1> result1;
IEnumerable<T2> result2;

using(var context1 = new MyContext())
using(var context2 = new MyContext())
{
    var result1Task = context1.Set<T1>().ToListAsync();
    var result2Task = context2.Set<T2>().ToListAsync();

    await Task.WhenAll(result1Task, result2Task).ConfigureAwait(false);

    result1 = result1Task.Result;
    result2 = result1Task.Result;
}

另一种方法是将其包装在自己的方法中:

// could also be written as generic method GetResultAsync<T>(),
// but you should get the point :)
async Task<IEnumerable<T1>> GetResult1Async()
{
    using(var context = new MyContext())
        return await context.Set<T1>().ToListAsync().ConfigureAwait(false);
}

async Task<IEnumerable<T2>> GetResult2Async()
{
    using(var context = new MyContext())
        return await context.Set<T2>().ToListAsync().ConfigureAwait(false);
}

var result1Task = GetResult1Async();
var result2Task = GetResult2Async();

await Task.WhenAll(result1Task, result2Task).ConfigureAwait(false);

var result1 = result1Task.Result;
var result2 = result1Task.Result;

两者都有很多样板代码,所以我想写一个用于打开/处理上下文对象的概括。

我想把它简化成这样:

var result1Task = repository.Set<T1>().ToListAsync();
var result2Task = repository.Set<T2>().ToListAsync();

await Task.WhenAll(result1Task, result2Task).ConfigureAwait(false);

var result1 = result1Task.Result;
var result2 = result1Task.Result;

诀窍是我希望repository.Set&lt;T&gt;() 返回IQueryable&lt;T&gt;,这样我就可以使用所有Linq 方法。为此,我正在尝试创建自己的IQueryProvider,在其 Execute 方法中包装上下文 using-Block。

这是我目前的课程:

public class RepositoryQueryProvider<TContext> : IQueryProvider
    where TContext : DbContext, new()
{
    // some irrelevant code here

    public TResult Execute<TResult>(Expression expression)
    {
        using (var context = new TContext())
        {
            var efProvider = ?; // how to get the provider from the context?
            return efProvider.Execute<TResult>(expression);
        }
    }
}

【问题讨论】:

  • 刚刚新建上下文并直接查询表有什么问题?
  • DbContext 是 IDisposable,因此需要将其包装在 using 语句中。然而,这种方式很难与 Task.WhenAll 一起使用。
  • 您只需在右括号之前调用Task.WhenAll...举个例子,这样我们就可以看到您要解决的实际问题
  • 我编辑了问题以概述潜在问题,希望对您有所帮助
  • 根据它所在的框架,您可以使用 DI、WebApi 或 MVC 请求周期。因此,当您的班级要求 DbContext 时,您可以为其提供一个临时的。

标签: c# entity-framework iqueryable iqueryprovider


【解决方案1】:

这很简单:

dbcontext.GetService<IAsyncQueryProvider>();

而且我认为不需要对 DbContext 使用“使用”

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多