2017-07-01 35 views
4

我有以下代碼應該得到一些book,並檢索該書(Book實體)的前兩個tagTag實體)。 因此TagsBook實體的navigation property實體框架6:Skip()&Take()不生成SQL,而是在加載到內存後過濾結果集。或者我做錯了什麼?

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探查表明我的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財產和/或刪除.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] */ 

你曾經與實體框架6工作時遇到同樣的問題?

是否有任何解決方法來克服這個問題,或者我設計了一個錯誤的方式查詢......?

感謝您的任何提示!

+0

爲什麼使用Skip,Take和SingleOrDefault ?.如果你不關心標籤的數量,只需替換Skip()。Take()。SingleOrDefault()with .FirstOrDefault() –

+0

@SebastianBrand老實說,我打算做分頁... by Skip(toBeSkipped )。取(pageSize的)'。我會更新問題以使其更清楚。 –

回答

4

正如@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的溶液的微小的變化是:

東西EF理解

1).Where(tag => tag.Books.Any(book => book.Id == firstBook.Id))替換

.Where(tag => tag.Books.Contains(firstBook))

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 
5

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理解的內容。

+0

謝謝!你是對的。爲了使其工作,我必須對解決方案做一些小的更改。當我運行代碼時(** As is **),我得到以下異常:未處理的異常:System.NotSupportedException:無法創建類型爲'Repositories.Implementation.Book'的常量值。在此上下文中僅支持基本類型或枚舉類型。但在替換後**替換** '.Where(tag => tag.Books.Contains(firstBook))'with'.Where(tag => tag.Books.Any(book => book.Id == firstBook。 Id))**我使用* LINQ to SQL *獲得了我試圖構造**的SQL查詢。 –

+1

@ Andrey-WD我的第二個想法應該是'.Where(tag => tag.Books.Select(book => book.Id).Contains(firstBook.Id))',但是您的查詢看起來也是正確的。真高興你做到了。 – hvd

相關問題