我最近一直在使用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