温故知新C#中 IEnumerable 与IQueryable

Posted dotNET跨平台

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了温故知新C#中 IEnumerable 与IQueryable相关的知识,希望对你有一定的参考价值。

微信公众号:趣编程ACE
关注可了解更多的.NET日常实战开发技巧,如需源码 后台回复 源码 即可;
如果觉得对你有帮助,欢迎关注

老生常谈 C#中 IEnumerable 与IQueryable

IEnumerableIQueryable 对于.Neter来说并不陌生,今天我就着重阐述下两者加载方式的异同。


前文回顾

【温故知新】C# Linq中 Select && SelectMany 使用技巧

IEnumerable<T>

  • 1.接口位于命名空间System.Collections中,是可以使用foreach进行枚举集合的基接口

  • 2.里面有一个GetEnumeartor()方法用来迭代集合,不是线程安全的 调用MoveNext()来顺序读取下一个集合中对象

  • 3.不支持在集合上添加、删除对象

  • 4.支持延迟执行,主要是yield 关键字

  • 5.不支持延迟加载,不适用于分页场景

  • 6.读取数据库或者服务数据时,IEnumerable将所有数据查询出放置内存中,然后再进行相应筛选操作

  • 7.对于内存中的数据,我们使用IEnumerable来操作

好了,那我们通过代码来演示下IEnumerable为啥不在服务端进行过滤筛选操作?

  1. 新建一个基于.net6的控制台程序

2.安装SqlLite的EFCore依赖包

1Install-Package Microsoft.EntityFrameworkCore.Sqlite

3.创建实体

1public class BloggingContext : DbContext
 2
 3    public DbSet<Blog> Blogs  get; set; 
 4    public DbSet<Post> Posts  get; set; 
 5
 6    public string DbPath  get; 
 7
 8    public BloggingContext()
 9    
10        var folder = Environment.SpecialFolder.LocalApplicationData;
11        var path = Environment.GetFolderPath(folder);
12        DbPath = System.IO.Path.Join(path, "blogging.db");
13    
14
15    // The following configures EF to create a Sqlite database file in the
16    // special "local" folder for your platform.
17    protected override void OnConfiguring(DbContextOptionsBuilder options)
18        => options.UseSqlite($"Data Source=DbPath");
19
20
21public class Blog
22
23    public int BlogId  get; set; 
24    public string Url  get; set; 
25
26    public List<Post> Posts  get;  = new();
27
28
29public class Post
30
31    public int PostId  get; set; 
32    public string Title  get; set; 
33    public string Content  get; set; 
34
35    public int BlogId  get; set; 
36    public Blog Blog  get; set; 
37

4.创建数据库

1Install-Package Microsoft.EntityFrameworkCore.Tools
2Add-Migration InitialCreate
3Update-Database

5.对数据库进行插入和读取操作

1using System;
 2using System.Linq;
 3
 4using var db = new BloggingContext();
 5
 6Console.WriteLine($"数据库路径: db.DbPath.");
 7
 8// Create
 9Console.WriteLine("Inserting a new blog");
10db.Add(new Blog  Url = "http://blogs.msdn.com/adonet" );
11db.SaveChanges();
12
13// Read
14Console.WriteLine("Querying for a blog");
15IEnumerable<Blog> blog = db.Blogs;
16
17var data = blog.
18    Where(b => b.Url == "http://blogs.msdn.com/adonet").Take(2);
19
20foreach (var item in data)
21
22    Console.WriteLine(item);
23

6.为项目集成日志
一、建立一个ConsoleLogger日志类并继承ILogger接口

public IDisposable BeginScope<TState>(TState state)
 2
 3            return null;
 4
 5
 6public bool IsEnabled(LogLevel logLevel)
 7
 8   switch (logLevel)
 9   
10    case LogLevel.Trace:
11    case LogLevel.Information:
12    case LogLevel.None:
13        return false;
14    case LogLevel.Debug:
15    case LogLevel.Warning:
16    case LogLevel.Error:
17    case LogLevel.Critical:
18    default:
19        return true;
20   
21
22
23public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
24
25        Console.WriteLine($"Level:logLevel,EventId:eventId.Id,EventName:eventId.Name");
26        if(state !=null)
27        
28            Console.WriteLine($"State:state");
29        
30
31        if(exception!=null)
32        
33            Console.WriteLine($"Exception:exception.Message");
34        
35

二、创建一个ConsoleLoggerProvider类并继承ILoggerProvider接口

1public class ConsoleLoggerProvider : ILoggerProvider
 2
 3   public ILogger CreateLogger(string categoryName)
 4   
 5      return new ConsoleLogger();
 6   
 7
 8   public void Dispose()
 9   
10
11   
12

三、控制台引入日志服务

1var loggerFactory=db.GetService<ILoggerFactory>();
2loggerFactory.AddProvider(new ConsoleLoggerProvider());

通过上图箭头指向的控制台输出的sql语句,可以显然的看见IEnumerable在查询数据库是只进行了 select * from 操作,并没有在数据库里面进行我们相应的过滤操作,而是将所有的数据一窝蜂查出来然后灌入内存中,最后在内存中进行过滤操作。
那么我们将db.Blogs 改为IQueryable类型呢

1IQueryable<Blog> blog = db.Blogs;

很明显可以看出,IQueryable将语句转为了我们需要的sql,因为IQueryable接受一个表达式树,表达式树将我们语句拼接,最后转化为查询sql,就实现了在数据库层次的过滤筛选。

IQueryable

  • 1.IQueryable 位于System.Linq命名空间

  • 2.IQueryable 支持延迟执行

  • 3.IQueryable 支持延迟加载,因此适用于类分页的场景。

  • 4.本身也是扩展自IEnumerable

以上是关于温故知新C#中 IEnumerable 与IQueryable的主要内容,如果未能解决你的问题,请参考以下文章

C# 列出 IList 或 IEnumerable 作为参数

如何在 C# 中使用 Ienumerable 反转一系列元素?

C# 使用IENUMERABLE,YIELD

c# IEnumerable<T>

温故知新C# Linq中 Where使用技巧

C#内建接口:IEnumerable