Efcore 2.2- where 子句在选择后运行并且 returns 错误结果
Efcore 2.2- where clause runs after selection and returns false results
我有这个简单的查询:
Expression<Func<Tips, bool>> lastTipsPredicate = x => x.Status == (int)EnumGringo.LU_Status.active;
IQueryable<Tips> lastQueryBase(DbSet<Tips> t) => t.OrderByDescending(x => x.CreateDate).Take(6);
IEnumerable<Tips> latestTips = await base.GetAllByCondition(lastTipsPredicate, lastQueryBase);
这是我的基本存储库:
public virtual async Task<IEnumerable<TEntity>> GetAllByCondition(Expression<Func<TEntity, bool>> predicate, Func<DbSet<TEntity>, IQueryable<TEntity>> baseQuery = null)
{
IQueryable<TEntity> q = context.Set<TEntity>();
if (baseQuery != null)
{
q = baseQuery(context.Set<TEntity>());
}
return await q.Where(predicate).ToListAsync();
}
这会生成这个 sql 查询(来自探查器):
exec sp_executesql N'SELECT [t].[ID], [t].[CreateDate], [t].[Description], [t].[InsertedByGringo], [t].[IsRecommended], [t].[IsSubscribe], [t].[LanguageType], [t].[SeoId], [t].[Slug], [t].[Status], [t].[Title], [t].[UserID], [t].[ViewCount]
FROM (
SELECT TOP(@__p_0) [x].[ID], [x].[CreateDate], [x].[Description], [x].[InsertedByGringo], [x].[IsRecommended], [x].[IsSubscribe], [x].[LanguageType], [x].[SeoId], [x].[Slug], [x].[Status], [x].[Title], [x].[UserID], [x].[ViewCount]
FROM [Tips] AS [x]
ORDER BY [x].[CreateDate] DESC
) AS [t]
WHERE [t].[Status] = 1',N'@__p_0 int',@__p_0=6
其中 returns 只有 5 条记录,而不是我预期的 6 条,1 条记录被过滤掉,因为它有状态!=1.
虽然此查询是正确的并且 returns 最后 6 条记录:
SELECT top 6 [t].[ID], [t].[CreateDate], [t].[Description], [t].[InsertedByGringo], [t].[IsRecommended], [t].[IsSubscribe], [t].[LanguageType], [t].[SeoId], [t].[Slug], [t].[Status], [t].[Title], [t].[UserID], [t].[ViewCount]
FROM Tips as [t]
WHERE [t].[Status] = 1
ORDER BY [t].CreateDate DESC
如何生成第二个查询而不是第一个?
Efcore 2.2- where clause runs after selection and returns false results
这既不是 EF Core 也不是 LINQ 问题,而是您的存储库方法构建 LINQ 查询的方式。
如果您想先应用过滤 (Where
),然后选择性地应用其余的,那么您应该将 baseQuery
函数输入类型从 DbSet<TEntity>
更改为 IQueryable<TEntity>
,实现如下:
public virtual async Task<IEnumerable<TEntity>> GetAllByCondition(
Expression<Func<TEntity, bool>> predicate,
Func<IQueryable<TEntity>, IQueryable<TEntity>> baseQuery = null)
{
var q = context.Set<TEntity>()
.Where(predicate); // <-- (1)
if (baseQuery != null)
q = baseQuery(q); // <-- (2)
return await q.ToListAsync();
}
我有这个简单的查询:
Expression<Func<Tips, bool>> lastTipsPredicate = x => x.Status == (int)EnumGringo.LU_Status.active;
IQueryable<Tips> lastQueryBase(DbSet<Tips> t) => t.OrderByDescending(x => x.CreateDate).Take(6);
IEnumerable<Tips> latestTips = await base.GetAllByCondition(lastTipsPredicate, lastQueryBase);
这是我的基本存储库:
public virtual async Task<IEnumerable<TEntity>> GetAllByCondition(Expression<Func<TEntity, bool>> predicate, Func<DbSet<TEntity>, IQueryable<TEntity>> baseQuery = null)
{
IQueryable<TEntity> q = context.Set<TEntity>();
if (baseQuery != null)
{
q = baseQuery(context.Set<TEntity>());
}
return await q.Where(predicate).ToListAsync();
}
这会生成这个 sql 查询(来自探查器):
exec sp_executesql N'SELECT [t].[ID], [t].[CreateDate], [t].[Description], [t].[InsertedByGringo], [t].[IsRecommended], [t].[IsSubscribe], [t].[LanguageType], [t].[SeoId], [t].[Slug], [t].[Status], [t].[Title], [t].[UserID], [t].[ViewCount]
FROM (
SELECT TOP(@__p_0) [x].[ID], [x].[CreateDate], [x].[Description], [x].[InsertedByGringo], [x].[IsRecommended], [x].[IsSubscribe], [x].[LanguageType], [x].[SeoId], [x].[Slug], [x].[Status], [x].[Title], [x].[UserID], [x].[ViewCount]
FROM [Tips] AS [x]
ORDER BY [x].[CreateDate] DESC
) AS [t]
WHERE [t].[Status] = 1',N'@__p_0 int',@__p_0=6
其中 returns 只有 5 条记录,而不是我预期的 6 条,1 条记录被过滤掉,因为它有状态!=1.
虽然此查询是正确的并且 returns 最后 6 条记录:
SELECT top 6 [t].[ID], [t].[CreateDate], [t].[Description], [t].[InsertedByGringo], [t].[IsRecommended], [t].[IsSubscribe], [t].[LanguageType], [t].[SeoId], [t].[Slug], [t].[Status], [t].[Title], [t].[UserID], [t].[ViewCount]
FROM Tips as [t]
WHERE [t].[Status] = 1
ORDER BY [t].CreateDate DESC
如何生成第二个查询而不是第一个?
Efcore 2.2- where clause runs after selection and returns false results
这既不是 EF Core 也不是 LINQ 问题,而是您的存储库方法构建 LINQ 查询的方式。
如果您想先应用过滤 (Where
),然后选择性地应用其余的,那么您应该将 baseQuery
函数输入类型从 DbSet<TEntity>
更改为 IQueryable<TEntity>
,实现如下:
public virtual async Task<IEnumerable<TEntity>> GetAllByCondition(
Expression<Func<TEntity, bool>> predicate,
Func<IQueryable<TEntity>, IQueryable<TEntity>> baseQuery = null)
{
var q = context.Set<TEntity>()
.Where(predicate); // <-- (1)
if (baseQuery != null)
q = baseQuery(q); // <-- (2)
return await q.ToListAsync();
}