首页 > 编程语言 >C# :IQueryable & IEnumerable

C# :IQueryable & IEnumerable

时间:2024-06-03 20:49:07浏览次数:13  
标签:C# IQueryable IEnumerable System 查询 where public

image.png

1. IEnumerable

namespace System.Collections:

public interface IEnumerable
{
  public IEnumerator GetEnumerator ();
}

public interface IEnumerator
{
    pubilc object Current { get; }
    public bool MoveNext ();
    public void Reset ();
}

IEnumerable 只有一个方法 GetEnumerator(), 既实现IEnumerable的所有泛型集合,都具备可枚举(IEnumerator)的能力

IEnumerator 只有一个属性 Current,和两个方法 MoveNext() \ Reset()

通过 MoveNext()Current 可以不停地移动 enumerator 的位置并返回当前的元素。

Reset() 会将 enumerator 设置到初始位置,既第一个元素之前

2. IQueryable

namespace System.Linq:

public interface IQueryable<out T> : System.Collections.Generic.IEnumerable<out T>, System.Linq.IQueryable {}

public interface IQueryable : System.Collections.IEnumerable
{
    // 表达式树返回结果的元素类型
    public Type ElementType { get; }

    // 获取IQueryable实例的表达式树
    public System.Linq.Expressions.Expression Expression { get; }

    public System.Linq.IQueryProvider Provider { get; }
}

// 定义用于创建和执行IQueryable对象所描述的查询的方法
public interface IQueryProvider
{
   public System.Linq.IQueryable CreateQuery(System.Linq.Expressions.Expression expression);

   public System.Linq.IQueryable<TElement> CreateQuery<TElement> (System.Linq.Expressions.Expression expression);

   public object? Execute(System.Linq.Expressions.Expression expression);

   public TResult Execute<TResult> (System.Linq.Expressions.Expression expression);
}

IQueryable 继承 IEnumerable,所以 IQueryable 具备可枚举的能力。

IQueryable 中的 Expession / Provider 则用来实现LINQ to SQL,具体可以看接下来的2节详细解释。

3. LINQ to SQL

LINQ to SQL是.Net Framework v3.5的组件,是能够提供将关系数据作为对象管理的运行时基础结构。

以往,编程语言通过 API 访问数据库数据的时候,需要将查询语句转为文本字符串。LINQ to SQL则会将对象模型中的语言集成查询转换为SQL,并发给数据库执行。当返回结果时,LINQ to SQL会再转换回可以用编程语言处理额对象。

所以,当拥有一个查询的时候,并不意味着查询已经执行:

var q = from c in dbContext.Customers Where c.City == ":London" select c;

命令对象会保留描述查询的字符串,IQueryable 对象的 Expression。命令对象的 ExecuteReader() 方法执行后,以 DataReader 形式返回结果。IQueryable 对象通过 GetEnumerator() 方法返回 IEnumerator 结果。

如下 foreach 会执行两次 query,这种行为称为延迟执行

var q =
   from c in db.Customers
   where c.City == "London"
   select c;
// Execute first time
foreach (Customer c in q)
   Console.WriteLine(c.CompanyName);
// Execute second time
foreach (Customer c in q)
   Console.WriteLine(c.CompanyName);

如果提前将结果转为任意标准的集合类,可以避免重复执行。

var q =
   from c in db.Customers
   where c.City == "London"
   select c;
// Execute once using ToList() or ToArray()
var list = q.ToList();
foreach (Customer c in list)
   Console.WriteLine(c.CompanyName);
foreach (Customer c in list)
   Console.WriteLine(c.CompanyName);

更多资料:LINQ:.NET Language-Integrated查询

4. IEnumerable & IQueryable

4.1 Expression

针对 IEnumerable所设计的扩展方法都将表达式视为委托,而针对 IQueryable 的那些扩展方法用的则是表达式树(expression tree)

IQueryable 会解析表达式树,并把这棵树表示的逻辑转为 provider 能够操作的格式,将其放在离数据最近的地方去执行。即传输数据往往会少于 IEnumerable,总体性能更好。

借鉴 《Effective C#》中的例子,如下两种写法,返回的结果相同,但是工作方式却不同:

// 1. use IQueryable
var q = from c in dbContext.Customers Where c.City == ":London" select c;
var finalAnswer = from c in q order by c.Name select c;

// 2. use Enumerable
var q = (from c in dbContext.Customers where c.City == "London" select c).AsEnumerable();
var finaAnswer = from c in q order by c.Name select c;

方法1,采用的是 IQueryable内置的 LINQ to SQL,q的查询语句,会和 第二行的组合起来,即只需要向数据库发送一次调用,where和orderby会在同一次sql查询操作里完成

方法2,则是把数据库对象从 IQueryable 强制转为了 IEnumerable形式的标准可枚举对象,即先向数据库发送查询请求,获得所有的数据后,放在本地进行排序操作

假如每种方法第二行还有一次 where 筛选一部分数据,那么方法1会组合2次 where,数据库只会返回最终目标数据集。而方法2会先从数据把所有第一次 where 得到的数据传到本地,之后在本地再次筛选,无疑增加了网络数据传输量。

4.2 Provider

IQueryable 的 Provider 未必能支持每一种查询方式,只能支持某些固定的运算符、方法,所以一旦查询操作里面调用除此之外的方法,那么就有可能把序列当成 IEnumerable 来查询,而非 IQueryable,否则会抛出异常。

再上 《Effective c#》例子:

private bool isValidProduct(Product p) => p.ProductName.LastIndexOf('C') == 0;

// 1. 转为 Enumerable 执行
var q1 = from p in dbContext.Products.AsEnumerable() where isValidProduct(p) select p;

// 2. 直接执行 IsValidProduct
var q2 = from p in dbContext.Products where isValidProduct(p) select p;

方法1可以正常运行,只是在 AsEnumerable() 之后,查询必须在本地执行,where 字句内的逻辑由LINQ to Objects处理。

方法2则会抛出异常,因为IQueryProvider会把查询操作转为T-SQL,交由远端执行。

标签:C#,IQueryable,IEnumerable,System,查询,where,public
From: https://www.cnblogs.com/wenxin1225/p/18229578

相关文章

  • react 报错 元素隐式具有 "any" 类型,因为类型为 "string" 的表达式不能用于索引类型 "
    interfaceitemType{legoBlockId:string;legoBlockNumber:string;//其他属性...}colorListAll().then((res:{result:Array<itemType>})=>{//使用Record<string,any>或更具体的类型(如果已知)constdic:Record<string,any&......
  • ABC 309 E Family and Insurance
    题意一个家庭用一颗树来表示。其中有m个人买了保险,x[i]买的保险可以继承y[i]代,请问有多少人至少有一份保险思路感觉是比较水的E题了,我们采取bfs遍历,然后类似于最短路的想法来更新每个点可以继承的最大保险代数。最后扫一遍所有人,看他们的dis有多少大于等于0,即为答案(dis最初所有......
  • Transformer Architecture
    TransformerArchitecture前面我们完成了自己训练一个小模型,今天我们结合论文来学习一下Transformer的理论知识~概述Transformer模型于2017年在论文《注意力就是你所需要的一切》中首次提出。Transformer架构旨在训练语言翻译目的模型。然而,OpenAI的团队发现transformer......
  • MACSHA256加密生成签名
    再水一篇,也是业务测试中遇到的一种加密方式,这里示例就直接使用相同的加密规则了,可以根据业务场景自行调整加密前字符串加密规则  所有API的请求参数(除去Sign参数),参数名转小写后根据参数名称的AscII表顺序排序;    将排序号的参数名和参数值拼装在一起得到新的字符串A; ......
  • ABC 308E MEX
    题意给定长度为N的包含0,1,2的a序列,和一个长度为N的包含字符M,E,X的字符串s。对于所以符合条件的1<=i<j<k<=N,使得s[i]s[j]s[k]=="MEX"的三元组(i,j,k),请你求出所有mex(a[i],a[j],a[k])之和。mex()函数表示未出现在序列中的最小非负整数。思路我们先看一个非常典的题目,给你一串由a......
  • 郑州大学计算机网络实验04 TCP协议探索和连接管理分析
    实验四:TCP协议探索和连接管理分析【实验目的】1、掌握TCP协议数据格式;2、掌握TCP首部各字段含义;3、掌握TCP建立连接和释放连接的过程;4、熟悉Linux下truncate命令的使用方法;5、了解Linux中利用nc命令开启远程shell的方法。【实验步骤与结果记录】要求:根据实验指导书中的......
  • 阿里开源superAGI代码分析【prompt部分】-核心还是react
    superAGI.txtYouareSuperAGIanAIassistanttosolvecomplexproblems.Yourdecisionsmustalwaysbemadeindependentlywithoutseekinguserassistance.PlaytoyourstrengthsasanLLMandpursuesimplestrategieswithnolegalcomplications.Ifyouh......
  • C语言程序设计第二讲:顺序程序设计
    一、数据类型1.基本数据类型C语言中提供了一些基本数据类型,用于表示各种不同类型的数据:整数类型:int:表示整数,通常占用4个字节。shortint:表示短整数,通常占用2个字节。longint:表示长整数,通常占用4或8个字节。longlongint:表示更长的整数,通常占用8个字节。unsignedi......
  • c#学习-(委托的高级使用)
    一、多播委托(multicast)&&单播委托        一个委托内部封装不止一个方法usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;usingSystem.Threading;namespacesix_multicast{internal......
  • c++——vector
    c++——vectorvector的介绍vector的简介迭代器的作用vector的迭代器失效问题可能导致vector迭代器失效的操作vector的模拟实现完整代码vector.hTest.h代码测试结果vector的介绍vector的文档介绍vector的简介vector是表示可变大小数组的序列容器。vector采用的连......