Entity Framework 6:Skip() & Take() 不生成SQL,而是加载到内存后过滤结果集。还是我做错了什么?
Entity Framework 6: Skip() & Take() do not generate SQL, instead the result set is filtered after loading into memory. Or am I doing something wrong?
我有以下代码应该获取一些 book
,并从那本书(Book
实体)中检索前 2 tag
s(Tag
实体) .
所以 Tags
是 Book
实体的 navigation property
。
using (var context = new FakeEndavaBookLibraryEntities())
{
Book firstBook = context.Set<Book>().Take(1).First();
var firstTwoTags = firstBook.Tags.OrderBy(tag => tag.Id).Skip(0).Take(2).ToList();
}
我期望 获得必须由 EF 生成的以下 SQL 查询。
SELECT TOP(2)
[Extent2].[Id] AS [Id],
[Extent2].[Version] AS [Version],
[Extent2].[Name] AS [Name]
FROM [Literature].[BookTagRelation] AS [Extent1]
INNER JOIN [Literature].[Tag] AS [Extent2]
ON [Extent1].[TagId] = [Extent2].[Id]
WHERE [Extent1].[BookId] = 1 /* @EntityKeyValue1 - [BookId] */
相反,EF Profiler 向我显示 EF 正在生成 无限结果集(如 SELECT * FROM ...)
SELECT [Extent2].[Id] AS [Id],
[Extent2].[Version] AS [Version],
[Extent2].[Name] AS [Name]
FROM [Literature].[BookTagRelation] AS [Extent1]
INNER JOIN [Literature].[Tag] AS [Extent2]
ON [Extent1].[TagId] = [Extent2].[Id]
WHERE [Extent1].[BookId] = 1 /* @EntityKeyValue1 - [BookId] */
Here is a scheme fragment if you need it
我还尝试将附加.AsQueryable()
到firstBook.Tags
属性and/or删除.Skip(0)
方法作为如下所示,但这也没有帮助。
var firstTwoTags = firstBook.Tags.AsQueryable().OrderBy(tag => tag.Id).Skip(0).Take(2).ToList();
同样的不良行为:
SELECT [Extent2].[Id] AS [Id],
[Extent2].[Version] AS [Version],
[Extent2].[Name] AS [Name]
FROM [Literature].[BookTagRelation] AS [Extent1]
INNER JOIN [Literature].[Tag] AS [Extent2]
ON [Extent1].[TagId] = [Extent2].[Id]
WHERE [Extent1].[BookId] = 1 /* @EntityKeyValue1 - [BookId] */
您在使用 Entity Framework 6 时遇到过同样的问题吗?
是否有解决方法来解决这个问题,或者我以错误的方式设计了查询...?
感谢任何提示!
firstBook.Tags
是延迟加载的 IEnumerable<Tag>
。在第一次访问时,所有标签都被加载,随后尝试将其变成 IQueryable<Tag>
无效,因为您没有从可以合理查询的内容开始。
相反,从已知的商品开始 IQueryable<Tag>
。类似于
Tag firstTag = context.Set<Tag>()
.Where(tag => tag.Books.Contains(firstBook))
.OrderBy(tag => tag.Id).Skip(0).Take(1).SingleOrDefault();
应该可以。您可能需要稍作调整才能将过滤条件变成 EF 可以理解的内容。
正如@hvd 指出的那样,我必须使用 IQueryable<Tag>
,而 firstBook.Tags
导航 属性 只是延迟加载 IEnumerable<Tag>
。
所以这是我的问题的解决方案,基于@hvd的回答。
Tag firstTag = context.Set<Tag>() // or even context.Tags
.Where(tag => tag.Books.Any(book => book.Id == firstBook.Id))
.OrderBy(tag => tag.Id)
.Skip(0).Take(1)
.SingleOrDefault();
所以@hvd的解决方案的小改动是:替换 the
.Where(tag => tag.Books.Contains(firstBook))
和
Something that EF understands
1) .Where(tag => tag.Books.Any(book => book.Id == firstBook.Id))
.
或
2) .Where(tag => tag.Books.Select(book => book.Id).Contains(firstBook.Id))
任何代码序列 (1) 或 (2) 都会生成以下 SQL 查询,这绝对是 不再是 一个 无界结果集.
SELECT [Project2].[Id] AS [Id],
[Project2].[Version] AS [Version],
[Project2].[Name] AS [Name]
FROM (SELECT [Extent1].[Id] AS [Id],
[Extent1].[Version] AS [Version],
[Extent1].[Name] AS [Name]
FROM [Literature].[Tag] AS [Extent1]
WHERE EXISTS (SELECT 1 AS [C1]
FROM [Literature].[BookTagRelation] AS [Extent2]
WHERE ([Extent1].[Id] = [Extent2].[TagId])
AND ([Extent2].[BookId] = 1 /* @p__linq__0 */))) AS [Project2]
ORDER BY [Project2].[Id] ASC
OFFSET 0 ROWS
FETCH NEXT 1 ROWS ONLY
我有以下代码应该获取一些 book
,并从那本书(Book
实体)中检索前 2 tag
s(Tag
实体) .
所以 Tags
是 Book
实体的 navigation property
。
using (var context = new FakeEndavaBookLibraryEntities())
{
Book firstBook = context.Set<Book>().Take(1).First();
var firstTwoTags = firstBook.Tags.OrderBy(tag => tag.Id).Skip(0).Take(2).ToList();
}
我期望 获得必须由 EF 生成的以下 SQL 查询。
SELECT TOP(2)
[Extent2].[Id] AS [Id],
[Extent2].[Version] AS [Version],
[Extent2].[Name] AS [Name]
FROM [Literature].[BookTagRelation] AS [Extent1]
INNER JOIN [Literature].[Tag] AS [Extent2]
ON [Extent1].[TagId] = [Extent2].[Id]
WHERE [Extent1].[BookId] = 1 /* @EntityKeyValue1 - [BookId] */
相反,EF Profiler 向我显示 EF 正在生成 无限结果集(如 SELECT * FROM ...)
SELECT [Extent2].[Id] AS [Id],
[Extent2].[Version] AS [Version],
[Extent2].[Name] AS [Name]
FROM [Literature].[BookTagRelation] AS [Extent1]
INNER JOIN [Literature].[Tag] AS [Extent2]
ON [Extent1].[TagId] = [Extent2].[Id]
WHERE [Extent1].[BookId] = 1 /* @EntityKeyValue1 - [BookId] */
Here is a scheme fragment if you need it
我还尝试将附加.AsQueryable()
到firstBook.Tags
属性and/or删除.Skip(0)
方法作为如下所示,但这也没有帮助。
var firstTwoTags = firstBook.Tags.AsQueryable().OrderBy(tag => tag.Id).Skip(0).Take(2).ToList();
同样的不良行为:
SELECT [Extent2].[Id] AS [Id],
[Extent2].[Version] AS [Version],
[Extent2].[Name] AS [Name]
FROM [Literature].[BookTagRelation] AS [Extent1]
INNER JOIN [Literature].[Tag] AS [Extent2]
ON [Extent1].[TagId] = [Extent2].[Id]
WHERE [Extent1].[BookId] = 1 /* @EntityKeyValue1 - [BookId] */
您在使用 Entity Framework 6 时遇到过同样的问题吗?
是否有解决方法来解决这个问题,或者我以错误的方式设计了查询...?
感谢任何提示!
firstBook.Tags
是延迟加载的 IEnumerable<Tag>
。在第一次访问时,所有标签都被加载,随后尝试将其变成 IQueryable<Tag>
无效,因为您没有从可以合理查询的内容开始。
相反,从已知的商品开始 IQueryable<Tag>
。类似于
Tag firstTag = context.Set<Tag>()
.Where(tag => tag.Books.Contains(firstBook))
.OrderBy(tag => tag.Id).Skip(0).Take(1).SingleOrDefault();
应该可以。您可能需要稍作调整才能将过滤条件变成 EF 可以理解的内容。
正如@hvd 指出的那样,我必须使用 IQueryable<Tag>
,而 firstBook.Tags
导航 属性 只是延迟加载 IEnumerable<Tag>
。
所以这是我的问题的解决方案,基于@hvd的回答。
Tag firstTag = context.Set<Tag>() // or even context.Tags
.Where(tag => tag.Books.Any(book => book.Id == firstBook.Id))
.OrderBy(tag => tag.Id)
.Skip(0).Take(1)
.SingleOrDefault();
所以@hvd的解决方案的小改动是:替换 the
.Where(tag => tag.Books.Contains(firstBook))
和
Something that EF understands
1) .Where(tag => tag.Books.Any(book => book.Id == firstBook.Id))
.
或
2) .Where(tag => tag.Books.Select(book => book.Id).Contains(firstBook.Id))
任何代码序列 (1) 或 (2) 都会生成以下 SQL 查询,这绝对是 不再是 一个 无界结果集.
SELECT [Project2].[Id] AS [Id],
[Project2].[Version] AS [Version],
[Project2].[Name] AS [Name]
FROM (SELECT [Extent1].[Id] AS [Id],
[Extent1].[Version] AS [Version],
[Extent1].[Name] AS [Name]
FROM [Literature].[Tag] AS [Extent1]
WHERE EXISTS (SELECT 1 AS [C1]
FROM [Literature].[BookTagRelation] AS [Extent2]
WHERE ([Extent1].[Id] = [Extent2].[TagId])
AND ([Extent2].[BookId] = 1 /* @p__linq__0 */))) AS [Project2]
ORDER BY [Project2].[Id] ASC
OFFSET 0 ROWS
FETCH NEXT 1 ROWS ONLY