Linq2Entities CompiledQuery用于使用连接的查询

时间:2012-03-28 12:49:39

标签: c# entity-framework entity-framework-4 linq-to-entities

我的查询效果不佳,例如生成的SQL代码是次优的。

原始陈述看起来像这样(简化):

ctx.Table1.Where(t => ...)
          .OrderBy(t => ....)
          .Select(t => new {Table1 = t,
                            SomeProperty = t.Table2.SomeProperty,
                            SomeProperty2 = t.Table2.SomeProperty2,
                            AnotherProperty = t.Table3.AnotherProperty,
                            ...
                            }

我查看了SQL Profiler,发现生成的SQL会多次连接同一个表,并且该语句大约需要1秒才能执行。

然后我将声明重写为以下内容:

from t in ctx.Table1
join t2 in ctx.Table2 on t.key equals t2.key into lt2
from t2 in lt2.DefaultIfEmpty()
join t3 in ctx.Table3 on t.key equals t3.key into lt3
from t3 in lt3.DefaultIfEmpty()
where t ...
orderby t...
select new {Table1 = t, .... }

这产生了一个更好的声明,当从SQL分析器中获取并在Management studio中执行时,它的速度是前一个示例中代码生成的语句的两倍。

但是,在运行第二个示例中的代码时,EF生成表达式所花费的时间远远超过了从查询优化中获得的时间。

那么我该如何将第二号语句写成CompiledQuery。我基本上不知道如何从CompiledQuery返回匿名类型。

2 个答案:

答案 0 :(得分:0)

我发现使用CompiledQueries的解决方法是:

  1. 在使用LINQ to Entity的每个QueryX()方法之前添加一个私有InitQueryX()方法。
  2. 使用属性和反射调用Init()方法中的所有InitQueryX()方法。
  3. 在应用启动时调用一次Init()方法。
  4. 这会强制在开始时编译查询,但是能够以比CompiledQueries更灵活的方式编写查询。

    InitQueryX()应该使用多个虚拟输入,以便它覆盖QueryX()方法中的所有路径(类似于单元测试代码覆盖率)。

    如果可能,InitQueryX()的输入应该是导致数据库中0行的模拟,这样Init()方法将花费更少的时间来运行。

答案 1 :(得分:0)

如果您的返回对象具有8个或更少属性,则可以使用Tuple类。如果您有更多属性但不想为这些属性声明类,则可以使用dynamic作为返回类型。