Entity Framework没有将Where子句作为WHERE子句发送到SQL Server。

17 浏览
0 Comments

Entity Framework没有将Where子句作为WHERE子句发送到SQL Server。

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

我想获取特定站点的所有“公开”帖子(我已经有一个名为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;

结果一样。

我在这里做了什么基本愚蠢的事情吗?

Entity Framework总是在客户端过滤吗?

谢谢!

Daniel

0
0 Comments

问题的出现原因是因为LINQ to Objects和LINQ to Entities的区别。当对ObjectContext发出查询时,实际上是在使用LINQ to Entities。这将返回一个IQueryable对象。只要您使用的是IQueryable类型的变量,就可以使用LINQ API进一步组合查询,并且在最终枚举结果时,它将转换为SQL语句。

但是您说:

(我有一个已经由EF带来的名为site的变量)

在这里,您正在查询对象的属性,因此您实际上是在使用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。我认为这样更清晰。

0
0 Comments

Entity Framework不会将Where子句作为WHERE子句发送到SQL Server的问题的原因是,当将Func传递给.Where方法时,过滤函数是在查询从数据库返回后应用的。这是因为.Where方法的返回值是IEnumerable类型。另一方面,如果将Expression>传递给.Where方法,过滤函数会生成一个发送到数据库的where子句。这是因为.Where方法返回的是IQueryable类型。只要使用IQueryable,就可以构建要发送到数据库的查询。当返回一个IEnumerable时,方法之前的所有内容都用于创建查询,而IEnumerable之后的所有内容都应用于返回的结果。这只在将lambda函数存储在变量中时才真正会产生影响。如果将lambda直接传递给.Where方法,通常不会出现问题。希望这对您有所帮助!

解决方法是使用Expression>来构建查询,而不是使用Func。这样,Entity Framework会将过滤函数作为WHERE子句发送到SQL Server。

以下是IEnumerable和IQueryable的区别:

- IEnumerable接口表示一个泛型集合,它是一个只能在内存中操作的序列。当您在查询中使用IEnumerable时,查询将在内存中执行。

- IQueryable接口表示一个可查询的数据源,它可以在内存中执行,也可以将查询转换为SQL语句并在数据库中执行。当您在查询中使用IQueryable时,查询将被转换为SQL语句并发送到数据库。

您可以在以下链接中了解更多关于IEnumerable和IQueryable的信息:

- 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

0