从CRUD到高级功能:EF Core在.NET Core中全面应用(四)

初识表达式树

表达式树:是一种可以描述代码结构的数据结构,它由一个节点组成,节点表示代码中的操作、方法调用或条件表达式等,它将代码中的表达式转换成一个树形结构,每个节点代表了代码中的操作例如,如果你有一个简单的C#表达式x => x.Name == "John",EFCore会将其转化为一个表达式树,这里我们可以通过Expression构建表达式树,如下所示:

cs 复制代码
Exception<Func<Book, bool>> e1 = b => b.Price > 5;
Exception<Func<Book, double>> e2 = (b1,b2) => b1.Price + b2.Price;

查看表达式树:这里我们可以通过断点调试,鼠标放在e1上面,点击右键点击快速监视,点击DebugView可以看到文本可视化工具, 如下所示:

整个表达式树是一个"或"类型的节点,左节点(Left)是b.Price>5的表达式,右节点(Right)是另外一个表达式,而b.Price>5这个表达式又是一个大于类型的节点 ,当然我们也可以看一下e2,通过快速监视可以看到其节点类型是相加类型,左边是b1右边是b2:

总结:Expression对象存储了运算逻辑,它把运算逻辑保存成抽象语法树(AST),可以在运行时动态获取运算逻辑,而普通委托则没有。

构建表达式树

只有通过代码动态构建表达式树才能更好的发挥表达式树的能力,ParameterExpression、BinaryExpression、MethodCallExpression、ConstantExpression等类几乎都没有提供构造方法,而且所有属性也几乎都是只读的。因此我们一般不会直接创建这些类的实例,而是调用Expression类的Parameter、MakeBinary、Call、Constant等静态方法来生成,这些静态方法我们一般称作创建表达式树的工厂方法,而属性则通过方法参数类设置。

ParameterExpression:表示表达式树中的一个参数,通常用于函数参数或 Lambda 表达式中的参数。

我们不能直接创建 ParameterExpression,而是通过 Expression.Parameter 方法来生成,如下:4

cs 复制代码
var param = Expression.Parameter(typeof(User), "u");

BinaryExpression:表示两个操作数之间的二元操作,例如加法、减法、比较等。我们可以通过 Expression.MakeBinary 方法来构建。

cs 复制代码
var left = Expression.Property(param, "Age");
var right = Expression.Constant(18);
var binaryExpression = Expression.MakeBinary(ExpressionType.GreaterThan, left, right);

MethodCallExpression:表示调用方法的表达式。例如,调用 ToString() 方法。我们通过 Expression.Call 来创建它。

cs 复制代码
var method = Expression.Call(param, typeof(User).GetMethod("ToString"));

ConstantExpression:表示常量的值,通常用于表达式中的常量部分。通过 Expression.Constant 方法来创建。

cs 复制代码
var constant = Expression.Constant(42);

通过组合这些表达式,我们可以构建一个完整的 Lambda 表达式。例如,构建一个 x => x.Age > 18 的表达式:

cs 复制代码
var param = Expression.Parameter(typeof(User), "x");
var ageProperty = Expression.Property(param, "Age");
var ageGreaterThan = Expression.Constant(18);
var condition = Expression.GreaterThan(ageProperty, ageGreaterThan);

var lambda = Expression.Lambda<Func<User, bool>>(condition, param);

通过组合多个表达式,我们可以构建更复杂的表达式。例如,使用逻辑操作符(AND、OR)来构建复合条件表达式:

cs 复制代码
var left = Expression.GreaterThan(Expression.Property(param, "Age"), Expression.Constant(18));
var right = Expression.Equal(Expression.Property(param, "Name"), Expression.Constant("John"));
var combined = Expression.AndAlso(left, right);

var lambda = Expression.Lambda<Func<User, bool>>(combined, param);

总结:通过使用 Expression 类提供的静态工厂方法(如 Expression.Parameter、Expression.MakeBinary、Expression.Call 等),我们可以动态地构建表达式树。这种方式使得我们能够灵活地生成查询条件或操作逻辑,特别是在需要构建动态查询或条件时非常有用。

相关推荐
GJGCY2 小时前
财务智能体落地实践:RPA、大模型与规则引擎如何构建业财自动化闭环?
经验分享·ai·自动化·财务·智能体
汇策研习社5 小时前
改良版ADX指标实战指南:告别传统ADX滞后、震荡误判难题
大数据·经验分享·金融·区块链·fastbull
tcpinchezhuwu6 小时前
教育行业AI落地实践:夜灯公考AI选岗与智能答疑系统架构解析
经验分享
cszn20267 小时前
AI如何自动识别PDF转换废标风险?智能评审项目实践
经验分享
卡梅德生物科技小能手7 小时前
卡美德生物科普MMP9(基质金属蛋白酶9):细胞外基质重塑的关键调节因子
经验分享·深度学习·生活
yyt3630458418 小时前
KlineChartQuant Tooltip 高频交互 200FPS 性能优化完整复盘
前端·经验分享·性能优化·typescript·vue·交互·chrome devtools
LuminousCPP9 小时前
C 语言集中实践全记录:顺序表 + 单链表原理实现与通讯录项目实战【附可运行源码】
c语言·开发语言·数据结构·经验分享·笔记
浩瀚地学14 小时前
【面试算法笔记】0202-链表-基本功能实现
java·经验分享·笔记·算法·面试
cszn202615 小时前
AI如何自动识别投标报价废标风险?智能评审项目实践
经验分享
神明不懂浪漫1 天前
【第四章】CSS(二)——文本外观属性与复合选择器
前端·css·经验分享·笔记