C# 当使用';包括';使用实体框架的语句
我在从实体框架中提取数据时遇到了包含问题。我昨天发布了一个非常类似的问题,这个问题与我将要使用的示例相同。我使用的是实体框架v4.0 我有以下简单的模型,一个包含页面表单列表的表(~200)。每个表单有一个或多个字段(总计约4000个),每个字段可能有一些参数(总计约16000个) 我使用以下代码提取数据:C# 当使用';包括';使用实体框架的语句,c#,entity-framework,entity-framework-4,C#,Entity Framework,Entity Framework 4,我在从实体框架中提取数据时遇到了包含问题。我昨天发布了一个非常类似的问题,这个问题与我将要使用的示例相同。我使用的是实体框架v4.0 我有以下简单的模型,一个包含页面表单列表的表(~200)。每个表单有一个或多个字段(总计约4000个),每个字段可能有一些参数(总计约16000个) 我使用以下代码提取数据: EntityConnection myConnection = new EntityConnection("name=myModel"); if(conn.State != Connec
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();
现在我对查询的这一部分感兴趣:
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倍)
编辑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)
);
IQueryable myFilteredObjectSet=myObjectSet
.其中(c=>c.FormID==1)
.其中(a=>a.FormFields
.其中(c=>c.FormFieldParameters
.Any(d=>d.FieldID==c.FieldID))
.Any(b=>b.FormID==1)
);
这会使查询正确过滤,并且运行得更快。然而,我确信这不是最好的解决方法,因为嵌套的Where/Any语句很快就会成为一场噩梦,当你有超过一把include时,它就成了一场噩梦。一定有更好的方法吗?已应用筛选-您的查询包含
其中1=[Extent1].[FormID]
。它实际上只加载您请求的日期。数据库中的查询引擎将正确评估您的查询,并将使用一些优化技术有效地筛选记录。很抱歉,但我确信这是不正确的。如果手动更新查询以包含内部where子句,则查询运行速度会快得多。我将更新我的问题来说明这一点。好吧,现在它变成了完全不同的问题,因为您以前的问题是关于返回错误的数据,而新的问题是关于不同的性能。是的,EF查询的性能可能要差得多,但唯一的解决办法是不使用Linq和EF并编写您自己的SQL查询。我想您误解了-在这两种情况下,我得到的数据与预期完全一致。问题是生成的查询是从整个“FormField”表中选择的,而该查询只应从FormID==1的表中选择。我知道在使用EF时会有开销,但这是一个巨大的性能损失,我确信我一定是做错了什么。请参阅我的问题,了解一个解决方法,它是有效的,但与sin一样丑陋。我相信一定有更好的方法。不幸的是,你没有做错任何事。您可以尝试使用.NET4.5-可能会有一些性能改进,将其作为错误报告给,将其作为改进请求报告给,或在上打开设计讨论。您还可以从codeplex下载EF源代码,并尝试自己修复它。这种解决方法不会急于加载您的关系。即使您添加了Include,它仍然不会过滤Include,因为它似乎急切地为我加载一切正常,并且我运行的sql探查器只显示了一个正在进行的调用—这是在我调用可查询对象上的.ToList()
时。
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]
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)
);