2017-05-30 61 views
-1

爲什麼EF生成一個查詢,以便以下內容不生成結果行並且首先引發異常。儘管在結果中包含Count,爲什麼此EF查詢不返回結果?

IQueryable<EntityName> repo = GetQuery<EntityName>(); 
IQueryable<EntityName> query = repo.Where(x => x.Discriminator == 1); 
var result = repo.Select(x => new 
{ 
    TotalRecords = query.Count(), 
    Results = query.Skip(request.Skip).Take(request.Take).ToList() 
}).First(); 

這個技巧允許我在EF中的單個數據庫調用下運行多個查詢;我打電話給任意庫repo,並返回一個新的對象,其中每個屬性是一個子查詢。只要存在query IQueryable中的記錄,就會生效。然而,我驚訝地發現當query中沒有記錄時,沒有任何返回(即query.Count()不包含在結果中)。我認爲即使query中沒有實體,這樣的查詢也應該產生結果行,因爲它涉及Count(),但它不返回任何內容。我懷疑這與EF必須在底層生成一個單一的結果集有關。

+0

不要緊,什麼是'Select'內,結果計數總是一樣的輸入設置。 'First'(或'Take(1)')可以將其限制爲最大1,即0或1.這基本上是SQL查詢行爲,而不是EF。 –

回答

1

這是真的,Count方法總是返回一個值,但與你的絕招的問題是,它是一個外select查詢(repo.Select(x => ...)的一部分,所以結果集的基數被包含的記錄數控制在外部查詢repo - 當它爲空時,結果將爲空,因此FirstOrDefault將返回null並且根本不會執行裏面的子查詢。

不同的數據庫有解決這些問題的不同的機制 - 例如,甲骨文將使用稱爲dual特殊的單記錄表,SQL Server允許SELECT沒有FROM等,但由於EF是通用的,它不能使用任何這些(以及,從技術上講,如果整個事物是以標準方式抽象出來的,並且實際的實現被委託給實際的提供者,但它沒有完成)。

儘管如此LINQ提供了一種方法(由EF支持)來強制一組通過使用DefaultIfEmpty方法返回至少1結果。通過使用

var result = repo.DefaultIfEmpty().Select(x => ... 

現在,因爲子查詢是完全無關的x,可以消除用於生產單外結果db表:應該在外部查詢應用的Select操作之前

var result = repo.Where(_ => false).DefaultIfEmpty().Select(x => ... 

這裏repo可以是任何IQueryable<T>只要它從DbContext起源,以獲得正確IQueryProvider

相關問題