使用实体框架使用“包含”语句引用时,关联表将被完全解析

时间:2012-07-31 12:36:22

标签: c# entity-framework entity-framework-4

从实体框架中提取数据时,我遇到了包含问题。我昨天发布了一个非常类似的问题here,它有我将要使用的相同样本。我正在使用Entity Framework v4.0。

我有以下简单模型,一个包含页面表单列表(~200)的表。每个表单都有一个或多个字段(总共约4000个),每个字段可能有一些参数(总共约16000个)。

Entity model

我使用以下代码来提取数据:

EntityConnection myConnection = new EntityConnection("name=myModel");

if(conn.State != ConnectionState.Open) {
    conn.Open();
}
ObjectContext context = new ObjectContext("name=myModel");
context.ContextOptions.LazyLoadingEnabled = false;

ObjectQuery<PageForm> myObjectSet = context.CreateObjectSet<PageForm>()
                                           .Include("FormFields.FormFieldParameters");

IQueryable<PageForm> myFilteredObjectSet = myObjectSet.Where(c => c.FormID == 1);

List<PageForm> myReturnValue = myFilteredObjectSet.toList();

其中生成以下sql查询

SELECT 
[Project1].[FormID] AS [FormID], 
[Project1].[FormName] AS [FormName], 
[Project1].[C2] AS [C1], 
[Project1].[FormID1] AS [FormID1], 
[Project1].[FieldID] AS [FieldID], 
[Project1].[FieldName] AS [FieldName], 
[Project1].[C1] AS [C2], 
[Project1].[FieldParamID] AS [FieldParamID], 
[Project1].[Value] AS [Value], 
[Project1].[FieldID1] AS [FieldID1]
FROM ( 
    SELECT 
    [Extent1].[FormID] AS [FormID], 
    [Extent1].[FormName] AS [FormName], 
    [Join1].[FieldID] AS [FieldID], 
    [Join1].[FieldName] AS [FieldName], 
    [Join1].[FormID] AS [FormID1], 
    [Join1].[FieldParamID] AS [FieldParamID], 
    [Join1].[Value] AS [Value], 
    [Join1].[FieldID1] AS [FieldID1], 
    CASE WHEN ([Join1].[FieldID] IS NULL) THEN CAST(NULL AS int) WHEN ([Join1].[FieldParamID] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1], 
    CASE WHEN ([Join1].[FieldID] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C2]
    FROM  [dbo].[PageForm] AS [Extent1]
    LEFT OUTER JOIN (
        SELECT 
        [Extent2].[FieldID] AS [FieldID], 
        [Extent2].[FieldName] AS [FieldName], 
        [Extent2].[FormID] AS [FormID], 
        [Extent3].[FieldParamID] AS [FieldParamID], 
        [Extent3].[Value] AS [Value], 
        [Extent3].[FieldID] AS [FieldID1]
        FROM  [dbo].[FormField] AS [Extent2]
        LEFT OUTER JOIN [dbo].[FormFieldParameter] AS [Extent3] ON [Extent2].[FieldID] = [Extent3].[FieldID] 
    ) AS [Join1] ON [Extent1].[FormID] = [Join1].[FormID]
    WHERE 1 = [Extent1].[FormID]
) AS [Project1]
ORDER BY [Project1].[FormID] ASC, [Project1].[C2] ASC, [Project1].[FieldID] ASC, [Project1].[C1] ASC

现在我对这部分查询感兴趣:

LEFT OUTER JOIN (
    SELECT 
    /**/
    FROM  [dbo].[FormField] AS [Extent2]
    LEFT OUTER JOIN [dbo].[FormFieldParameter] AS [Extent3] ON [Extent2].[FieldID] = [Extent3].[FieldID] 
) AS [Join1] ON [Extent1].[FormID] = [Join1].[FormID]

这似乎查询了整个FormField和FormFieldParameter表,没有应用过滤。所以,我认为正在发生的是,使用.Include("FormField.FormFieldParameter")类似于说 - “并在结果查询中返回这些表中的所有数据”。我真正想要的是“只返回这些表中与过滤的PageForm表相关的数据”。

有办法做到这一点吗?很抱歉,如果这个问题听起来太简单,或类似于我之前提出的问题,但我真的无法理解实体框架的内部。

编辑1:

如果我将上面的示例更改为包含where子句的以下示例,那么查询的速度要快几个数量级(大约快10倍)。

LEFT OUTER JOIN (
    SELECT 
    /**/
    FROM  [dbo].[FormField] AS [Extent2]
    LEFT OUTER JOIN [dbo].[FormFieldParameter] AS [Extent3] ON [Extent2].[FieldID] = [Extent3].[FieldID] 
    WHERE 1 = [Extent2].[FormID]
) AS [Join1] ON [Extent1].[FormID] = [Join1].[FormID]

编辑2:

更多信息。我已经想到如果我在初始查询中添加一些时髦的过滤,我可以强制运行一个更有效的查询。

IQueryable<PageForm> myFilteredObjectSet = myObjectSet
                                          .Where(c => c.FormID == 1)
                                          .Where(a => a.FormFields
                                                       .Where(c => c.FormFieldParameters
                                                                    .Any(d => d.FieldID == c.FieldID))
                                                       .Any(b => b.FormID == 1)
                                           );

这会导致查询正确过滤,并且运行速度更快。但是,我确信这不是解决这个问题的最佳方法,因为嵌套的Where / Any语句很快就会变成一个噩梦,当你有少数几个包含时。必须有更好的方法吗?

1 个答案:

答案 0 :(得分:0)

应用过滤 - 您的查询包含WHERE 1 = [Extent1].[FormID]。它确实只加载你要求的日期。数据库中的查询引擎将正确评估您的查询,它将使用一些优化技术来有效地过滤记录。