我最近一直在使用SQL服務器分析器,並注意到爲我認爲應該工作的代碼生成兩個不同查詢的奇怪行爲。顯然,我錯了,因此這個問題。爲什麼實體框架爲非常相似的代碼創建了不同的SQL查詢
讓我們從頂部開始。我有一個非常簡單的庫類,它包含以下幾個方法:
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]
和看起來像整個表的負載。有人可以解釋這種負載行爲的細微差異嗎? 謝謝
謝謝!你可能會推薦一些文獻/文章,這些文章/文章將EF比「crud」更深入一些,這樣我可以在將來避免類似的問題? – neurotix
嚴格地說,'Func/Expression'的區別更像是一個LINQ問題,而不是EF問題(任何時候你沒有通過一個表達式,LINQ提供程序 - EF在你的情況下 - 將無法解釋它,唯一可以匹配的重載是Enumerable類中的重載)。還有一件值得一提的事情是,EF不支持'Queryable'導航屬性,這意味着每次你將Where()'(或任何其他LINQ方法)追加到它時,它會從數據庫中獲取整個數據,然後將使用Linq的方法應用到對象('Enumerable') –
haim770