当前位置: 首页 > news >正文

C# Web开发教程(四)

EF Core SQL性能优化底层原理之表达式树(Expression Trees)

好的,我们来详细探讨一下表达式树(Expression Trees)在 Entity Framework Core 中的核心作用。

简单来说,表达式树是 EF Core 能够将你的 C# 代码(如 LINQ 查询)翻译成高效 SQL 语句的基石。没有表达式树,EF Core 就无法实现其最核心、最有价值的功能。


核心作用:提供可翻译(Translatable)的查询结构

表达式树的核心作用在于,它不是一个可执行的方法,而是一个数据结构。这个数据结构可以被 EF Core 的查询提供程序(Query Provider,例如 SqlServerQueryProvider) 分析、解读,并最终转换为目标数据库的 SQL 语言。

1. 与委托(Delegate)的关键区别

要理解表达式树,最好先把它和普通的委托(如 Func<T, bool>)对比一下。

  • 使用 Func<T, bool>(委托,即内存中的方法):

    Func<Post, bool> myDelegate = p => p.Title.Contains("EF Core");
    

    这是一个可立即执行的代码。如果你在 DbSet<Post> 上使用 .Where(myDelegate),EF Core 无法看到 p.Title.Contains("EF Core") 这个逻辑。它只能调用这个方法,并得到返回的 truefalse。结果就是,EF Core 必须从数据库拉取所有 Post 数据到内存中,然后在客户端进行过滤。这在大多数情况下性能极差。

  • 使用 Expression<Func<T, bool>>(表达式树):

    Expression<Func<Post, bool>> myExpression = p => p.Title.Contains("EF Core");
    

    这是一个数据的描述。它不是一个可执行的方法,而是一个可以被遍历和检查的树形结构。EF Core 可以解析这棵树,发现它由以下节点组成:

    • 一个参数 p(类型为 Post
    • 访问 pTitle 属性
    • 调用 String.Contains 方法,参数是 "EF Core"
    • 等等...

    正因为 EF Core 能读懂你的意图,它才能生成对应的 SQL 语句:

    SELECT [p].[Id], [p].[Title], [p].[Content], ...
    FROM [Posts] AS [p]
    WHERE [p].[Title] LIKE N'%EF Core%'
    

    查询在数据库服务器上执行,只返回匹配的结果,效率极高。

2. 实现跨数据库平台的查询翻译

EF Core 支持多种数据库(SQL Server, SQLite, PostgreSQL, MySQL等)。其底层为每个数据库提供了不同的查询提供程序。

  • 表达式树提供了一个公共的、抽象的查询中间语言
  • 当你编写 LINQ 查询时,EF Core 会将其构建为表达式树。
  • 然后,SQL Server 提供程序会将其翻译成 T-SQL,而 SQLite 提供程序则会将其翻译成 SQLite 的 SQL 方言。

这个过程使得你可以用同一套 C# LINQ 代码与不同的数据库进行交互。

3. 实现高效的延迟执行(Deferred Execution)

著名的 IQueryable<T> 接口(提供 LINQ 查询功能的接口)的核心就是一个表达式树和一个查询提供程序。

IQueryable<Post> query = _context.Posts.Where(p => p.Likes > 10).OrderBy(p => p.CreatedDate);
  • 这行代码并没有立即执行查询。
  • 它只是构建了一个表达式树,将 .Where.OrderBy 操作依次组合起来。
  • 只有当你真正需要数据时(例如调用 .ToList().FirstOrDefault()foreach 循环),EF Core 才会将整个表达式树翻译成 SQL 并执行。

这种“组合性”是构建复杂动态查询的基础。

4. 支持动态查询构建

这是表达式树非常强大的一个高级用法。因为表达式树是可以在运行时动态构建和修改的,所以你可以在程序运行时根据用户输入或其他条件来动态创建查询。

示例:根据用户选择动态过滤

// 假设这是用户从前端传递过来的过滤条件
string searchTitle = "Hello";
DateTime? minDate = new DateTime(2023, 1, 1);// 从基础查询开始
IQueryable<Post> query = _context.Posts;// 动态添加 Where 条件
if (!string.IsNullOrEmpty(searchTitle))
{// 动态构建表达式: p => p.Title.Contains(searchTitle)query = query.Where(p => p.Title.Contains(searchTitle));
}if (minDate.HasValue)
{// 动态构建表达式: p => p.CreatedDate >= minDatequery = query.Where(p => p.CreatedDate >= minDate.Value);
}// 最终执行的 SQL 会组合所有条件
var results = query.ToList();

EF Core 会将所有动态添加的条件组合到最终的表达式树中,并生成一个包含所有过滤条件的单一、高效的 SQL 语句。


总结

表达式树在 EF Core 中的作用可以概括为以下几点:

作用 说明
查询翻译 最核心的作用。将 C# LINQ 代码转换为等价的 SQL 语句,确保查询在数据库端执行,而不是在客户端内存中。
提供抽象层 作为公共中间语言,使同一套 LINQ 代码可以跨不同数据库工作。
实现延迟执行 使得 IQueryable 可以组合多次查询操作,最后再统一翻译和执行。
支持动态查询 允许在运行时程序化地构建复杂的查询逻辑,极大提升了灵活性。

简而言之,表达式树是 EF Core 的“翻译官”,它让 C# 语言能够与 SQL 数据库进行高效、无缝的对话。 没有表达式树,LINQ to SQL 之类的 ORM 技术就无法实现其核心价值。

表达式树测试

  • 安装第三方库 Install-Package ExpressionTreeToString实现打印表达式树结构
......
using ExpressionTreeToString;
......
Expression<Func<Article, bool>> res = a => a.Price > 0; // 创建表达式树
Console.WriteLine(res.ToString("Object notation","C#")); // 使用 ExpressionTreeToString 输出表达式树- 结果:var a = new ParameterExpression {Type = typeof(Article),IsByRef = false,Name = "a"
};new Expression<Func<Article, bool>> {NodeType = ExpressionType.Lambda,Type = typeof(Func<Article, bool>),Parameters = new ReadOnlyCollection<ParameterExpression> {a},Body = new BinaryExpression {NodeType = ExpressionType.GreaterThan,Type = typeof(bool),Left = new MemberExpression {Type = typeof(int),Expression = a,Member = typeof(Article).GetProperty("Price")},Right = new ConstantExpression {Type = typeof(int),Value = 0}},ReturnType = typeof(bool)
}

总结

它:

  1. 展示了表达式树的内部结构层次
  2. 揭示了每个表达式节点的各种属性(如 NodeType, Type 等)
  3. 说明了表达式树是如何由多个嵌套表达式组成的
  4. 提供了如何手动构建相同表达式树的"配方"

虽然这个输出不能直接编译执行,但它对于理解表达式树的内部工作原理非常有帮助,特别是在调试复杂表达式或学习表达式树API时

http://www.wxhsa.cn/company.asp?id=853

相关文章:

  • HarmonyOS运动开发
  • 【2025-09-09】家庭决策
  • 【2025-09-08】社交活动
  • 【2025-09-07】连岳摘抄
  • 【2025-09-10】满37周岁
  • 文件摆渡系统排名榜Top5揭晓:第一名安全高效又便捷
  • 多变量递归-全排列问题
  • Gitee DevOps:中国开发者效率革命的本土化解决方案
  • EAS_单点登录跨数据中心问题
  • 鸿蒙应用开发从入门到实战(二):DevEco Studio工具安装
  • 飞驰云联出席“未来出行国际场景创新峰会” 赋能产业新征程!
  • Canvas 计算文字宽高性能高效,解决了开源项目中的一个棘手问题!
  • fastapi
  • 非线性技术之所以重要,是因为非线性问题不像线性问题那样可以统一求解,其复杂性往往要求我们结合理论、几何、数值、统计、甚至物理直觉进行处理。
  • Oracle主键primary key
  • Kubernetes标签(Label)
  • Gitee DevOps平台深度评测:本土化优势如何赋能企业研发效能提升
  • 【SPIE出版】2025计算机视觉和影像计算国际学术会议(CVIC 2025)
  • 密码学工具包中的Hash函数
  • 跟着院士导师做会议口头汇报PPT!
  • 【分享】内外网文件传输方式:从传统痛点到专业解决方案!
  • c# TargetFramework 应该写 net48 还是 net4.8
  • Docker 安装 Elasticsearch 报错
  • 大疆红外TSDK红外照片转RGB888图片JAVA实现方法
  • MCU联网
  • 算法-A*-01 - jack
  • 代码是上午写的,公司是下午解散的!
  • [antlr] 如何在Linux(Ubuntu)环境中安装配置antlr4.9.2
  • 国内开发者如何选择代码管理平台?Gitee、GitHub与Bitbucket深度对比
  • Spring-Android-即时入门-全-