c# - 为什么 Entity Framework 为非常相似的代码创建不同的 sql 查询

标签 c# .net entity-framework-6

我最近一直在研究 SQL Server 分析器,并注意到为一段代码生成两个不同查询的奇怪行为,在我看来,这两个查询应该工作相同。显然我错了,所以才有这个问题。

让我们从头开始。我有一个非常简单的存储库类,它包含以下方法:

 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> 时(这只是一个通用委托(delegate))到 Where()方法,你正在调用 Enumerable.Where() (而不是 Queryable.Where() )因此加载整个 DbSet到内存 - SQL 不会包含 WHERE条款。

参见 What is the difference between IQueryable<T> and IEnumerable<T>?

关于c# - 为什么 Entity Framework 为非常相似的代码创建不同的 sql 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39494509/

相关文章:

.net - 在 backgroundworker 中使用 Thread.Sleep 方法有什么好处?

c# - 使用 TransactionScope 在一个事务中使用多个数据库(多个 DbContext)

c# - 如何编写高效的 sql 查询以从多个表中进行选择?

c# - 将指针函数移植到 C#

c# - 乌鸦数据库 : What's wrong with this multi-map/reduce index?

c# - Entity Framework linq orderby 函数

c# - Entity Framework - 使用类继承创建模型

c# - 如何在 C# 中强制解锁文件?

c# - 如果选择列表项,则实现 CanExecute 以启用按钮

c# - 设计问题