![](/img/trans.png)
[英]Why does Entity Framework 6 generate complex SQL queries for simple lookups?
[英]Why does Entity Framework create a different sql queries for very similar code
我最近一直在使用SQL Server Profiler,並注意到為代碼生成兩個不同查詢的奇怪行為,我認為這些查詢應具有相同的功能。 顯然我錯了,因此這個問題。
讓我們從頭開始。 我有一個非常簡單的存儲庫類,其中包含以下方法:
public virtual TEntity GetSingle(Func<TEntity, bool> where, bool asNoTracking = true, params Expression<Func<TEntity, object>>[] includedNavigationProperties)
{
IQueryable<TEntity> dbQuery = this.ResolveIQueryableForType<TEntity>(asNoTracking, includedNavigationProperties);
return dbQuery.Where(where).FirstOrDefault();
}
public virtual IQueryable<TEntity> AsQueryable(bool asNoTracking = true, params Expression<Func<TEntity, object>>[] includedNavigationProperties)
{
IQueryable<TEntity> dbQuery = this.ResolveIQueryableForType<TEntity>(asNoTracking, includedNavigationProperties);
return dbQuery;
}
private IQueryable<TEntityType> ResolveIQueryableForType<TEntityType>(bool asNoTracking, params Expression<Func<TEntityType, object>>[] includedNavigationProperties)
where TEntityType : class
{
IQueryable<TEntityType> dbQuery = _context.Set<TEntityType>();
// Apply eager loading
if (includedNavigationProperties != null)
{
foreach (Expression<Func<TEntityType, object>> navigationProperty in includedNavigationProperties)
{
dbQuery = dbQuery.Include<TEntityType, object>(navigationProperty);
}
}
if (asNoTracking)
{
return dbQuery.AsNoTracking();
}
else
{
return dbQuery;
}
}
稍后在應用程序中,我將執行此調用(其中AccessTokenRepository是我的存儲庫類型的對象):
accessToken = _repository.AccessTokenRepository.AsQueryable().Where(x => x.AccessTokenID == accessTokenId).FirstOrDefault();
導致此查詢:
exec sp_executesql N'SELECT TOP (1)
[Extent1].[AccessTokenID] AS [AccessTokenID],
[Extent1].[IssuedUtc] AS [IssuedUtc],
[Extent1].[ExpiresUtc] AS [ExpiresUtc],
[Extent1].[ValidForTimeSpan] AS [ValidForTimeSpan],
[Extent1].[CreatedDateTime] AS [CreatedDateTime]
FROM [dbo].[AccessToken] AS [Extent1]
WHERE [Extent1].[AccessTokenID] = @p__linq__0',N'@p__linq__0 uniqueidentifier',@p__linq__0='62A1BE60-3569-4E80-BC8E-FC01B0FFC266'
但是類似的調用(我會說應該導致相同的SQL):
accessToken = _repository.AccessTokenRepository.GetSingle(x => x.AccessTokenID == accessTokenId);
結果是:
SELECT
[Extent1].[AccessTokenID] AS [AccessTokenID],
[Extent1].[IssuedUtc] AS [IssuedUtc],
[Extent1].[ExpiresUtc] AS [ExpiresUtc],
[Extent1].[ValidForTimeSpan] AS [ValidForTimeSpan],
[Extent1].[CreatedDateTime] AS [CreatedDateTime]
FROM [dbo].[AccessToken] AS [Extent1]
這看起來像整個表的負載。 有人可以解釋一下負載行為的細微差別嗎? 謝謝
這是因為GetSingle
方法的第一個參數定義為
Func<TEntity, bool> where
代替
Expression<Func<TEntity, bool>> where
當您將該Func<TEntity, bool>
(這只是一個通用委托)傳遞給Where()
方法時,您正在調用Enumerable.Where()
(而不是Queryable.Where()
),從而加載整個DbSet
為內存-SQL將不包含WHERE
子句。
您的GetSingle
方法將Func<>
作為參數,這將強制將IQueryable<>
強制轉換為IEnumerable<>
,從而導致查詢“完成”(執行的查詢將具有由表達式創建的形式,直到集合關閉為止-cast),然后在內存中執行每個后續操作。 您必須使用Expression<Func<>>
以便引擎可以正確分析表達式樹並生成正確的查詢。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.