c# - 如何为 linq / EF Core 中的 where 语句编写动态谓词构建器?
问题描述
我正在处理IQueryable<SomeRandomObject>
使用 EF Core 3.1 数据上下文提取的数据。
我很确定我可以动态地构建一个谓词,.Where()
这样我就可以为哪一列和什么值传递一个字符串。
当然这不起作用,但一些伪代码可能是:
IQueryable myQueryable = stuffFromContext;
var columnName = "memberid";
var searchValue = "1234";
var results = myQueryable.Where(x=> someMagicColumnFunction(columnName, searchvalue))
在这一点上我只做过研究,谓词构建不是我的专业领域。
有人可以帮我创建一个函数,我可以传入参数 my IQueryable
,一个表示列名的字符串和一个用于搜索的字符串(现在完全相等,没有'like')。
我很想看看这是怎么做到的。我在任何地方都找不到一个可靠的例子来说明如何做这样的小事。大多数例子都是一切和厨房水槽!
解决方案
假设行的类型是,myQueryable
那么TQueryable
您可以创建一个myQueryable
特定的函数来生成 lambda:
Expression<Func<TQueryable, bool>> EqualsFilter<TCol>(string columnName, TCol searchValue) {
// build x => x.{columnName} == searchValue
// (TQueryable x)
var xParam = Expression.Parameter(typeof(TQueryable), "x");
// x.{columnName}
var colExpr = Expression.Property(xParam, columnName);
// {searchValue}
var constExpr = Expression.Constant(searchValue);
// x.{columnName} == {searchValue}
var lambdaBody = Expression.MakeBinary(ExpressionType.Equal, colExpr, constExpr);
// (TQueryable x) => x.{columnName} == {searchValue}
var lambda = Expression.Lambda<Func<TQueryable, bool>>(lambdaBody, xParam);
return lambda;
}
一旦你有了这个方法,你可以像这样使用它:
var myQueryable = stuffFromContext;
var columnName = "memberid";
var searchValue = "1234";
var results = myQueryable.Where(EqualsFilter(columnName, searchvalue));
但是,如果myQueryable
具有复杂或匿名类型(由于 a Select
or Join
),则需要替换Where
为 C# 只能从参数推断类型,因此您需要myQueryable
参数来获取要过滤的实体类型。使用通用版本的EqualsFilter
作为辅助方法,您有:
public static class IQueryableExt {
static Expression<Func<T, bool>> EqualsFilter<T, TCol>(string columnName, TCol searchValue) {
// build x => x.{columnName} == searchValue
// (T x)
var xParam = Expression.Parameter(typeof(Accounts), "x");
// x.{columnName}
var colExpr = Expression.Property(xParam, columnName);
// {searchValue}
var constExpr = Expression.Constant(searchValue);
// x.{columnName} == {searchValue}
var lambdaBody = Expression.MakeBinary(ExpressionType.Equal, colExpr, constExpr);
// (T x) => x.{columnName} == {searchValue}
var lambda = Expression.Lambda<Func<T, bool>>(lambdaBody, xParam);
return lambda;
}
public static IQueryable<T> WhereColumnEquals<T, TCol>(this IQueryable<T> src, string columnName, TCol searchValue)
=> src.Where(EqualsFilter<T, TCol>(columnName, searchValue));
}
您现在可以使用如下:
var myQueryable = stuffFromContext;
var columnName = "memberid";
var searchValue = "1234";
var results = myQueryable.WhereColumnEquals(columnName, searchvalue);
推荐阅读
- c - 播种 srand() 一次 rand() 每次都给出几乎相同的结果
- java - JDA Discord 向消息添加反应
- android - Xamarin UI 测试在单击 app.PressMenu 后选择菜单选项
- c# - C# 循环关于指数数
- php - (Symfony\Component\Console\Exception\CommandNotFoundException) 命令“新”未定义
- sql - 如何在一条 SQL 语句中使用两次 GROUP BY 语句?
- flutter - Flutter AssetEntity 名称与资产名称
- html - 编译 Azure DevOps 小部件期间发生错误:无法解析“TFS/Dashboards/WidgetHelpers”
- spring - 在为 spring-boot 做贡献时,如何运行单元测试?
- python - 在另一个 Django 模型字段中重用主键