从实体框架中提取数据时,我遇到了包含问题。我昨天在这里发布了一个非常相似的问题,它与我将要使用的示例相同。我正在使用实体框架 v4.0。
我有以下简单模型,一个包含页面表单列表(~200)的表格。每个表单都有一个或多个字段(总共约 4000 个),每个字段可能有一些参数(总共约 16000 个)。
我使用以下代码提取数据:
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 表相关的数据”。
有没有办法做到这一点?抱歉,如果这个问题听起来太简单,或者与我之前的问题相似,但我真的很难理解 Entity Framework 的内部结构。
编辑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)
);
这会导致查询正确过滤,并且运行得更快。但是,我确信这不是解决此问题的最佳方法,因为当您拥有多个 Include 时,嵌套的 Where/Any 语句很快就会变成一场噩梦。一定会有更好的办法?