在连接中使用委托CompiledQuery

本文关键字:CompiledQuery 连接 | 更新日期: 2023-09-27 18:07:07

我有一个与我之前的问题相关的问题。在现有的LINQ位涉及许多连接,我试图采取每个独立的方法,包括连接并将其转换为CompiledQuery

首先,常规LINQ方法:

private IQueryable<Widget> GetWidgetQuery()
{
    return db.Widgets.Where(u => (!u.SomeField.HasValue || !u.SomeField.Value));
}

这里,CompiledQuery的委托(字段)定义如下:

private static readonly Func<DBDataContext, IQueryable<Widget>> GetWidgetQuery = 
    CompiledQuery.Compile((DBDataContext db) => 
    db.Widgets.Where(u => (!u.SomeField.HasValue || !u.SomeField.Value)));

如果我将鼠标悬停在方法GetWidgetQuery()的正常LINQ语句上,我看到它是方法,如下所示:

(method) IQueryable<Widget> GetWidgetQuery()
然而,编译后的查询委托(字段)有如下不同:

(field) Func<DBDataContext, IQueryable<Widget>> GetWidgetQuery

将后者作为LINQ语句的一部分执行时,语法不同如下。首先,普通LINQ参与join:

var myquery =
    from wxr in GetWidgetXRQuery()
    join w in GetWidgetQuery() on wxr.WidgetID equals w.ID
    select new DTO.WidgetList
    {
        ...
    }

这里,CompiledQuery以委托的形式调用:

var myquery =
    from wxr in GetWidgetXRQuery()
    join w in GetWidgetQuery.Invoke(myContext) on wxr.WidgetID equals w.ID
    select new DTO.WidgetList
    {
        ...
    }

前者返回预期的结果集;后者,当我尝试myquery.ToList()时,会产生一个stackoverflow异常,我认为这部分与。net 3.5的限制有关。

有人可以帮助我了解如何编译语句存在作为一个字段(或者我想我应该说一个委托),而不是一个方法是杀死我的查询?总之,我知道我做错了,但我不确定我明白我误解了什么。

在连接中使用委托CompiledQuery

我试着做你在EF 4上做的大致相同的事情,一切似乎都很好。因此,这要么是EF 3.5的问题,要么与您的GetWidgetXRQuery的实现有关,或者两者的某种组合。

但是我真正想说的是,正如Roy Goode在回答您前面的问题时所说的那样,一旦您以任何方式扩展了预编译查询,就会失去该查询的所有优点。通过尝试在查询上执行Join,可以将其转换为普通的旧查询。因此,您不妨使用似乎适合您的未编译版本。

更新

意识到你在谈论LINQ to SQL。这种查询似乎在实体框架中有支持,但不支持LINQ to SQL。在。net 4中,我得到以下错误:

不支持返回自引用常量表达式的IQueryable。

这对我来说并不意味着什么,但我猜它与内部表示编译查询的方式有关。如果我将查询求值为变量并稍后在查询中使用该变量,我仍然会得到相同的错误,因此它显然与委托和函数之间的区别无关。我仍然认为编译查询不适合在这里使用。您需要创建一个大的编译查询来表示您想要执行的整个查询,或者如果您想以这种方式将它们拼接在一起,则需要使用常规查询。

我在做db集成测试时遇到了同样的错误,直接跳到这一点,而不试图解释我的具体问题。Linq to Sql将在使用IQueryable内部创建Sql查询,当你在IQueryable上执行一个方法时,即ToList(),它会在数据库上执行该查询。所以在我的例子中,我加入了一个返回IQueryable的方法但被模拟为返回结果,它试图将其编译为sql查询但我创建的IQueryable没有内部sql查询