实体框架不将Where子句作为WHERE子句发送到SQL Server

时间:2010-02-11 02:47:53

标签: c# .net entity-framework where-clause

我有一个包含网站的简单数据库,每个网站都有一堆帖子。

我正在尝试获取某个站点的所有“公共”帖子(我有一个名为site的变量,它已经是EF提供的一个实例)

第一个显而易见的事情是:

  var posts = from post in site.Posts
              where post.Public == true
              orderby post.PublicationTime descending
              select post;

这给我带来了我想要的东西,但是在研究SQL Server Profiler时,WHERE只过滤Public字段,而不是Site。实际上,在SQL Server中运行Profiler捕获的查询确实会带回所有站点中的所有帖子(这显然会在ASP.Net方面稍后进行过滤)。

然后我尝试了:

  var posts = from post in db.Posts
              where post.Site == site && post.Public == true
              orderby post.PublicationTime descending
              select post;

同样的结果。

我在这里做了一些根本愚蠢的事情吗? 实体框架是否总是在客户端进行过滤?

谢谢!
丹尼尔

2 个答案:

答案 0 :(得分:9)

您需要了解LINQ to Entities和LINQ to Objects之间的区别。在使用实体框架时跟踪这一点非常重要。

当您针对ObjectContext发出查询时,您正在使用LINQ to Entities。这将返回IQueryable。只要您使用的是IQueryable类型的变量,就可以使用LINQ API进一步组合查询,当您最终枚举结果时,它将转换为SQL。

但你说:

  

(我有一个名为site的变量,它已经是EF带来的一个实例)

在这里,您要查询对象的属性,因此您正在使用LINQ to Objects,而不是LINQ to Entities。这意味着您的查询具有不同的提供程序,并且不会转换为SQL。

关于你的第二个问题:

var posts = from post in db.Posts
            where post.Site == site && post.Public == true
            orderby post.PublicationTime descending
            select post;

EF不允许您对L2E中的实例进行身份比较。你必须比较密钥。尝试:

var posts = from post in db.Posts
            where post.Site.Id == site.Id && post.Public
            orderby post.PublicationTime descending
            select post;

顺便说一句,我将post.Public == true更改为post.Public。我认为它更清洁。

答案 1 :(得分:4)

如果有人使用方法语法遇到问题:

如果将Func<TEntity,Boolean>传递给.Where方法,则在查询从数据库返回后应用过滤器函数。这是因为.Where方法的返回值返回IEnumerable。另一方面,如果将Expression<Func<TEntity,Boolean>传递给.Where方法,则过滤器函数会生成一个发送到数据库的where子句。这是因为.Where返回IQueryable。只要您坚持使用IQueryables,您就构建了要发送到数据库的查询。当您返回IEnumerable时,方法之前的所有内容都用于创建查询,并且IEnumerable之后的所有内容都应用于返回的内容。如果您将lambda函数存储在变量中,这才真正重要。如果您将lambda直接传递到.Where方法,通常不会有问题。希望这会有所帮助!!

IEnumerable Where:https://msdn.microsoft.com/en-us/library/bb549418(v=vs.110).aspx

IQueryable Where:https://msdn.microsoft.com/en-us/library/bb535040(v=vs.110).aspx