在连接中使用委托CompiledQuery?

Dar*_*ent 5 c# linq-to-sql

我有一个与我之前的问题相关的问题.在LINQ的现有位中涉及多个连接,我试图采用包含连接的每个单独方法并将其转换为CompiledQuery.

一,正常的LINQ方法:

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

在这里,CompiledQuery的委托(字段)定义沿着这些方向:

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

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

(method) IQueryable<Widget> GetWidgetQuery()
Run Code Online (Sandbox Code Playgroud)

但是,编译的查询委托(字段)不同如下:

(field) Func<DBDataContext, IQueryable<Widget>> GetWidgetQuery
Run Code Online (Sandbox Code Playgroud)

在作为LINQ语句的一部分执行后者时,语法不同如下.首先,正常LINQ参与加入:

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

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

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

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

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

Str*_*ior 1

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

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

更新

意识到您正在谈论 LINQ to SQL。实体框架似乎支持这种查询,但 LINQ to SQL 不支持。在 .NET 4 中,我收到以下错误:

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

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