代码改变世界

.IEnumerable和IQueryable两接口的区别

2023-12-18 15:01  钟铧若岩  阅读(118)  评论(0)    收藏  举报


1)所有对于IEnumerable的过滤、排序、分组、聚合等操作,都是在内存中进行的。也就是说把所有
的数据不管用不用得到,都从数据库倒入内存中,只是在内存中进行过滤和排序操作,但性能很高,空
间换时间,用于操作本地数据源。
2)所有对于IQueryable的过滤、排序、分组、聚合等操作,只有在数据真正用到的时候才会到数据
库中查询,以及只把需要的数据筛选到内存中。Linq to SQL引擎会把表达式树转化成相应的SQL在数据
库中执行,这也是Linq的延迟加载核心思想所在,在很复杂的操作下可能比较慢了,时间换空间。
3)操作本地数据源用IEnumerable,操作远程数据源用IQueryable

在 C# 中,IEnumerable<T> 和 IQueryable<T> 是两个用于处理数据集合的重要接口,它们存在诸多区别,下面为你详细介绍:

1. 命名空间与继承关系

  • IEnumerable<T>:属于 System.Collections.Generic 命名空间,它是 .NET 中处理集合的基础接口,许多集合类(如 List<T>Array 等)都实现了该接口。
  • IQueryable<T>:处于 System.Linq 命名空间,继承自 IEnumerable<T> 接口。这表明 IQueryable<T> 具备 IEnumerable<T> 的所有功能,同时还拥有额外的查询能力。

2. 执行方式

  • IEnumerable<T>:当使用 IEnumerable<T> 时,查询操作在内存中执行。也就是说,在执行查询之前,数据必须先加载到内存里。例如,对一个 List<T> 集合进行查询,查询逻辑会在内存中的集合上直接执行。

 

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
        // 使用 IEnumerable 进行查询
        var result = numbers.Where(n => n > 3);
        foreach (var num in result)
        {
            Console.WriteLine(num);
        }
    }
}

 

在上述代码中,numbers 是一个 List<int> 集合,实现了 IEnumerable<int> 接口。Where 方法会在内存中的 numbers 集合上执行筛选操作。

 

    • IQueryable<T>IQueryable<T> 主要用于处理远程数据源(如数据库),查询操作会被转换为相应的查询语句(如 SQL 语句),然后发送到数据源进行执行。数据不会全部加载到内存中,只有在需要时才会从数据源获取。
using System;
using System.Data.Entity;
using System.Linq;

// 假设这是一个实体类
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
}

// 假设这是一个数据库上下文类
public class ProductContext : DbContext
{
    public DbSet<Product> Products { get; set; }
}

class Program
{
    static void Main()
    {
        using (var context = new ProductContext())
        {
            // 使用 IQueryable 进行查询
            var query = context.Products.Where(p => p.Name.Contains("Apple"));
            foreach (var product in query)
            {
                Console.WriteLine(product.Name);
            }
        }
    }
}

  

在这个例子中,context.Products 实现了 IQueryable<Product> 接口。Where 方法会将查询条件转换为 SQL 语句,然后发送到数据库执行,只有符合条件的数据才会被返回。

3. 延迟执行

  • IEnumerable<T>:支持延迟执行,即查询不会立即执行,而是在迭代结果时才会执行。但由于它是在内存中执行,一旦开始迭代,查询就会立即在内存中的数据上执行。
  • IQueryable<T>:同样支持延迟执行,而且在执行查询之前可以不断地对查询进行组合和修改。只有在需要获取数据(如调用 ToList()First() 等方法)时,才会将最终的查询语句发送到数据源执行。

4. 性能差异

  • IEnumerable<T>:适用于处理内存中的小型数据集,因为它的查询操作是在内存中进行的,对于大数据集,频繁的内存操作可能会导致性能下降。
  • IQueryable<T>:在处理大数据集和远程数据源时具有优势,因为它可以将查询操作下推到数据源进行执行,减少了数据传输和内存开销。

5. 扩展方法的使用

  • IEnumerable<T>:使用的是 System.Linq.Enumerable 类中的扩展方法,这些方法在内存中对集合进行操作。
  • IQueryable<T>:使用的是 System.Linq.Queryable 类中的扩展方法,这些方法会将查询操作转换为适合数据源的查询语句。

 

综上所述,IEnumerable<T> 适用于内存中的数据处理,而 IQueryable<T> 更适合处理远程数据源和大数据集。