这篇文章主要给大家介绍了关于C#表达式中动态查询的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
前言
当您使用LINQ来处理数据库时,这种体验是一种神奇的体验,对吗?你把数据库实体像一个普通的收集,使用Linq中像Where,Select或者 Take,这些简单的使用就能让代码可用了。
但是,让我们考虑一下这里是如何通过动态查询和表达式树实现此功能的:幕后发生的事情。您编写的LINQ查询将转换为SQL(或其他方式),并将该SQL查询发送到数据库。然后将数据库的响应映射到C#对象。但是,如何完全转换为SQL?
在本文中,您将看到诸如Entity Framework和MongoDB C#驱动程序之类的框架如何使用表达式树进行转换。您将看到如何亲自使用表达式树来构建动态查询。这些查询是您无法在编译时创建的查询,因为您将知道该查询仅在运行时的外观。
对可查询树和表达式树进行揭秘
考虑以下使用Entity Framework 6的C#代码:
DbSet<Student> students = context.Students;
var billie = await students.Where(s => s.StudentName == "Billie").ToListAsync();
执行时,实体框架会产生以下SQL查询:
SQL:SELECT
[Extent1].[StudentID] AS [StudentID],
[Extent1].[StudentName] AS [StudentName],
[Extent1].[DateOfBirth] AS [DateOfBirth],
FROM [dbo].[Students] AS [Extent1]
WHERE N'Billie' = [Extent1].[StudentName]
请注意,WHERESQL查询中有一个操作。那不是很明显。如果SQL不包含WHERE,则所有学生都将从数据库中带走,并且筛选将在.NET进程中执行。实际上,以下代码可以做到这一点:
//BAD:
DbSet<Student> students = context.Students;
Func<Student, bool> predicate = s => s.StudentName == "Billie";
var x = students.Where(predicate).ToList();
在最后一个示例中,SQL查询使所有学生进入流程,并将其映射到常规集合。不同之处在于,在第一段代码中,lambda是一个Expression<Func<Student, bool>>,它允许实体框架将其添加到SQL查询中。在第二段代码中,lambda是a Func<Student, bool>,因此将Where执行操作符之前的所有操作并将其转换为常规IEnumerable集合,然后执行其余的查询。
第二段代码在性能,内存和网络方面很糟糕。我们从网络中获取了许多对象,而不是仅从数据库中获取一个项目。然后,我们使用CPU将它们序列化为C#对象。并用完内存将它们存储在进程的堆中。
因此,让我们回到第一段代码。如何await students.Where(s => s.StudentName == "Billie").ToListAsync()产生一个包含的SQL查询WHERE N'Billie' = [Extent1].[StudentName]?
答案是表达树。该代码s => s.StudentName == "Billie"实际上是一个结构化查询,可以通过编程将其分解为节点树。在此示例中,有6个节点。最顶层的节点是lambda表达式。左侧是lambda参数。在它的右边是Equal表示表达式的lambda主体。实体框架具有遍历这些表达式树并构造SQL查询的算法。其他数据源提供程序(如Mongo DB C#驱动程序)也会发生同样的事情,除了它会构造一个MongoDB json查询。
C#表达式树
在第一段代码中,类型s => s.StudentName == "Billie"为Expression<Func<Student, bool>>。这表示生成树的表达式树Func<Student, bool>。该Where子句接受这种类型的参数,因为aDbSet<TEntity>实现了IQueryable<T>接口,这要求它与表达式树配合使用。相反,常规集合(如数组或a List<T>)IEnumerable意味着它将lambdas => s.StudentName == "Billie"用作常规函数。
好的,但是我该如何利用它呢?
在大多数情况下,使用表达树的人们就是在构建世界实体框架的人们。但是在某些特定情况下,它变得非常有用。这是我们最近在Ozcode[1](我的日常工作)中遇到的一个用例:
我们想在名为Error的数据库实体上创建动态服务器端过滤。该实体具有许多属性,我们希望允许用户对其进行过滤。因此过滤应根据被允许Username,Country,Version,或任何其他财产。这是我们需要实现的API:
IQueryable<Error> _errors;
public IEnumerable<Error> GetErrors(string propertyToFilter, string value){ /*..*
本文标题为:C#表达式中的动态查询详解【译】
基础教程推荐
- C#类和结构详解 2023-05-30
- ZooKeeper的安装及部署教程 2023-01-22
- unity实现动态排行榜 2023-04-27
- winform把Office转成PDF文件 2023-06-14
- linux – 如何在Debian Jessie中安装dotnet core sdk 2023-09-26
- C#控制台实现飞行棋小游戏 2023-04-22
- C# List实现行转列的通用方案 2022-11-02
- 一个读写csv文件的C#类 2022-11-06
- C# windows语音识别与朗读实例 2023-04-27
- C# 调用WebService的方法 2023-03-09