如何在 LINQ where 子句中传递 func 表达式?
How to pass func expression in LINQ where clause?
这是我要传入 where 子句的自定义过滤器 (Func)
Func<Project,bool> filter = f =>
{
bool filteredContent = true;
if (!CreatorId.Equals(0))
filteredContent = f.CreatedBy.Equals(CreatorId);
if (filteredContent && !VerticalMarketId.Equals(0))
filteredContent = f.VerticalMarketsId.Equals(VerticalMarketId);
if (filteredContent && !ProductCategoryId.Equals(0))
filteredContent = f.ProductCategoriesId.Equals(ProductCategoryId);
return filteredContent;
};
这是我的代码,我根据在过滤器表达式中创建的条件获取所有项目
getProjects = await _context.Projects.Where(x => x.IsDeleted == false && filter.Invoke(x))// Here I'm getting the exception
.Include(PC => PC.ProjectComments.Where(x => x.IsDeleted == false))
.Include(SP => SP.SharedProjects)
.AsNoTracking().ToListAsync();
Exception:The LINQ expression (DbSet......) could not be
translated. Either rewrite the query in a form that can be translated,
or switch to client evaluation explicitly by inserting a call to
'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'.
谁能告诉我如何使用表达式过滤数据?
注意:我可以在应用过滤器之前执行 ToListAsync(),但它会从数据库中获取所有记录,然后在客户端进行过滤。但是我想在服务器端过滤数据。
如果您使用的 Linq To Objects
应该有效,但您正在使用 Linq To SQL
,在这种情况下,您必须考虑如何将此函数转换为有效的 SQL
语句。问问自己:如何在 SQL 语句中传递此函数调用?取决于你对表达式的主体做了什么,你不能把它翻译成SQL,你有时必须更简单。
候选解
在您的项目中添加 PredicateBuilder
class。它将为您提供轻松的逻辑运算符来处理表达式。
尝试定义一个表达式并将其作为参数传递给查询方法链的 Where
方法。示例(阅读评论):
// define a expression with default condition
Expression<Func<Project, bool>> filter = f => !f.IsDeleted;
// check conditions to add new filtes with `And` logical operator
if (!CreatorId.Equals(0))
filter = filter.And(f => f.CreatedBy.Equals(CreatorId));
else if (!VerticalMarketId.Equals(0))
filter = filter.And(f => f.VerticalMarketsId.Equals(VerticalMarketId));
else if (!ProductCategoryId.Equals(0))
filter = filter.And(f => f.ProductCategoriesId.Equals(ProductCategoryId));
// apply the filter on the query and execute it
getProjects = await _context.Projects.Where(filter)
.Include(PC => PC.ProjectComments.Where(x => !x.IsDeleted))
.Include(SP => SP.SharedProjects)
.AsNoTracking()
.ToListAsync();
注意:我没有测试这段代码,它可能应该以某种方式修复!
关于 Linq To 的重要提示 SQL:
- 逻辑运算符没问题,而且往往可以很好地翻译成 sql;
Where(x => x.Children.Any(j => j.Children.Any()))
,每个 Any
调用都会在查询范围内生成一个子查询,请谨慎使用,因为它可能会影响您的数据库性能。
- 如果您只需要检查某个项目是否存在,请使用
queryable.Any(expression)
。
- 如果你需要检查然后做某事,最好使用
queryable.FirstOrDefault(expression)
并在使用前检查结果是否为空。
- 使用
.Take(int)
和 .Skip(int)
的分页。
- 始终通过调用
.ToList()
、.ToArray()
或这些方法的异步版本来具体化您的查询。避免在顶层传递可查询的(查询可以在你想要的范围之外执行)。
我通过创建一个简单的表达式来解决这个问题,如下所示:
private static Expression<Func<Project, bool>> ProjectFilterExpression(
int creatorId,
int verticalMarketId,
int productCategoryId)
{
Expression<Func<Project, bool>> projectFilterExpression = pfe =>
!pfe.IsDeleted
//CreatorId Filter
&& (creatorId.Equals(0) || pfe.CreatedBy.Equals(creatorId))
//Vertical Market Filter
&& (verticalMarketId.Equals(0) || pfe.VerticalMarketsId.Equals(verticalMarketId))
// Product Category Filter
&& (productCategoryId.Equals(0) || pfe.ProductCategoriesId.Equals(productCategoryId));
return projectFilterExpression;
}
然后我在我的过滤器方法中调用这个静态方法。
var filter = ProjectFilterExpression(CreatorId, VerticalMarketId, ProductCategoryId);
最后我在我的 LINQ where 子句中应用了这个过滤器
getProjects = await _context.Projects.Where(filter).AsNoTracking().ToListAsync();
一切正常。
这是我要传入 where 子句的自定义过滤器 (Func)
Func<Project,bool> filter = f =>
{
bool filteredContent = true;
if (!CreatorId.Equals(0))
filteredContent = f.CreatedBy.Equals(CreatorId);
if (filteredContent && !VerticalMarketId.Equals(0))
filteredContent = f.VerticalMarketsId.Equals(VerticalMarketId);
if (filteredContent && !ProductCategoryId.Equals(0))
filteredContent = f.ProductCategoriesId.Equals(ProductCategoryId);
return filteredContent;
};
这是我的代码,我根据在过滤器表达式中创建的条件获取所有项目
getProjects = await _context.Projects.Where(x => x.IsDeleted == false && filter.Invoke(x))// Here I'm getting the exception
.Include(PC => PC.ProjectComments.Where(x => x.IsDeleted == false))
.Include(SP => SP.SharedProjects)
.AsNoTracking().ToListAsync();
Exception:The LINQ expression (DbSet......) could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'.
谁能告诉我如何使用表达式过滤数据?
注意:我可以在应用过滤器之前执行 ToListAsync(),但它会从数据库中获取所有记录,然后在客户端进行过滤。但是我想在服务器端过滤数据。
如果您使用的 Linq To Objects
应该有效,但您正在使用 Linq To SQL
,在这种情况下,您必须考虑如何将此函数转换为有效的 SQL
语句。问问自己:如何在 SQL 语句中传递此函数调用?取决于你对表达式的主体做了什么,你不能把它翻译成SQL,你有时必须更简单。
候选解
在您的项目中添加
PredicateBuilder
class。它将为您提供轻松的逻辑运算符来处理表达式。尝试定义一个表达式并将其作为参数传递给查询方法链的
Where
方法。示例(阅读评论):
// define a expression with default condition
Expression<Func<Project, bool>> filter = f => !f.IsDeleted;
// check conditions to add new filtes with `And` logical operator
if (!CreatorId.Equals(0))
filter = filter.And(f => f.CreatedBy.Equals(CreatorId));
else if (!VerticalMarketId.Equals(0))
filter = filter.And(f => f.VerticalMarketsId.Equals(VerticalMarketId));
else if (!ProductCategoryId.Equals(0))
filter = filter.And(f => f.ProductCategoriesId.Equals(ProductCategoryId));
// apply the filter on the query and execute it
getProjects = await _context.Projects.Where(filter)
.Include(PC => PC.ProjectComments.Where(x => !x.IsDeleted))
.Include(SP => SP.SharedProjects)
.AsNoTracking()
.ToListAsync();
注意:我没有测试这段代码,它可能应该以某种方式修复!
关于 Linq To 的重要提示 SQL:
- 逻辑运算符没问题,而且往往可以很好地翻译成 sql;
Where(x => x.Children.Any(j => j.Children.Any()))
,每个Any
调用都会在查询范围内生成一个子查询,请谨慎使用,因为它可能会影响您的数据库性能。- 如果您只需要检查某个项目是否存在,请使用
queryable.Any(expression)
。 - 如果你需要检查然后做某事,最好使用
queryable.FirstOrDefault(expression)
并在使用前检查结果是否为空。 - 使用
.Take(int)
和.Skip(int)
的分页。 - 始终通过调用
.ToList()
、.ToArray()
或这些方法的异步版本来具体化您的查询。避免在顶层传递可查询的(查询可以在你想要的范围之外执行)。
我通过创建一个简单的表达式来解决这个问题,如下所示:
private static Expression<Func<Project, bool>> ProjectFilterExpression(
int creatorId,
int verticalMarketId,
int productCategoryId)
{
Expression<Func<Project, bool>> projectFilterExpression = pfe =>
!pfe.IsDeleted
//CreatorId Filter
&& (creatorId.Equals(0) || pfe.CreatedBy.Equals(creatorId))
//Vertical Market Filter
&& (verticalMarketId.Equals(0) || pfe.VerticalMarketsId.Equals(verticalMarketId))
// Product Category Filter
&& (productCategoryId.Equals(0) || pfe.ProductCategoriesId.Equals(productCategoryId));
return projectFilterExpression;
}
然后我在我的过滤器方法中调用这个静态方法。
var filter = ProjectFilterExpression(CreatorId, VerticalMarketId, ProductCategoryId);
最后我在我的 LINQ where 子句中应用了这个过滤器
getProjects = await _context.Projects.Where(filter).AsNoTracking().ToListAsync();
一切正常。