簡體   English   中英

為什么實體框架針對非常相似的代碼創建不同的sql查詢

[英]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子句。

請參見IQueryable <T>和IEnumerable <T>有什么區別?

您的GetSingle方法將Func<>作為參數,這將強制將IQueryable<>強制轉換為IEnumerable<> ,從而導致查詢“完成”(執行的查詢將具有由表達式創建的形式,直到集合關閉為止-cast),然后在內存中執行每個后續操作。 您必須使用Expression<Func<>>以便引擎可以正確分析表達式樹並生成正確的查詢。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM