IQueryable & IEnumberable 区别

Namespace And Inheritances Relations

                  


?
1
2
3
4
5
6
7
8
9
Namespace: System.Collections
     [ComVisibleAttribute( true )]
     [GuidAttribute( "496B0ABE-CDEE-11d3-88E8-00902754C43A" )]
     public  interface  IEnumerable
Namespace: System.Collections.Generic
     public  interface  IEnumerable : IEnumerable
Namespace: System.Linq
     public  interface  IQueryable : IEnumerable
     public  interface  IQueryable : IEnumerable, IQueryable, IEnumerable
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
static  void  Main( string [] args)
         {
             //创建数据库访问网关
             using  (SchoolDBEntities schoolEntities = new  SchoolDBEntities())
             {
                 //查询的结果放入IQueryable接口的集合中
                 IQueryable<T_Class> classesIQue = (from c in  schoolEntities.T_Class
                                                    orderby c.ID
                                                      select c).Skip<T_Class>(3).Take<T_Class>(3);
                 //注意这个AsEnumerable<T_Class>()在分页查询之前,先将其转换成IEnumerable类型
                 IEnumerable<T_Class> classesIEnu = (from c in  schoolEntities.T_Class
                                                     orderby c.ID  
                                                     select c).AsEnumerable<T_Class>().Skip<T_Class>(3).Take<T_Class>(3);
                 //因为启用了延迟加载机制,所以下面调用一下,才会真正去读取数据库
                 int  i = 0;
                 foreach  (var c in  classesIQue)
                 {
                     i++;
                 }
                 Console.WriteLine(i);
                 foreach  (var c in  classesIEnu)
                 {
                     i++;
                 }
                 Console.WriteLine(i);
             }
             Console.WriteLine( "OK" );
             Console.ReadKey();
         }

第一种:直接返回 IQueryable类型的查询,如下图所示:

第二种:在用分页查询之前先将其转换成 IEnumerable实际执行的sql如下图所示:

总结

IQueryable接口与IEnumberable接口的区别:  IEnumerable<T> 泛型类在调用自己的SKip 和 Take 等扩展方法之前数据就已经加载在本地内存里了,而IQueryable<T> 是将Skip ,take 这些方法表达式翻译成T-SQL语句之后再向SQL服务器发送命令,它并不是把所有数据都加载到内存里来才进行条件过滤

(转载自:FlyDragon)

&lt;think&gt;好的,用户想了解如何在C#中使用IQueryable进行动态查询,特别是如何通过构建表达式树来实现。我需要结合他们提供的引用内容,尤其是引用[1]、[2]、[3]中的信息来解答这个问题。 首先,用户提到的IQueryable与IEnumerable的区别是关键。根据引用[2],IQueryable的扩展方法将逻辑封装为表达式树,而IEnumerable则使用委托。这意味着动态查询需要生成表达式树,以便LINQ提供程序(如Entity Framework)能将其转换为SQL或其他查询语言。 接下来,引用[1]和[3]都提到了表达式树的使用。动态构建查询条件的核心在于动态创建Expression对象。比如,用户可能需要根据不同的属性名和值来生成条件,这需要用到Expression.Property、Expression.Constant以及组合这些表达式的方法如Expression.Equal。 用户的问题可能涉及到如何拼接多个条件,比如动态添加多个过滤条件。这时需要使用Expression.AndAlso或Expression.OrElse来组合多个表达式。同时,参数表达式(ParameterExpression)必须保持一致,否则会出错,这一点需要特别注意。 另外,引用[3]中的示例代码展示了如何创建一个简单的比较表达式,并编译成委托。但如果是针对IQueryable,应该避免编译成委托,而是保持为表达式树,以便LINQ提供程序解析。因此,可能需要返回Expression&lt;Func&lt;T, bool&gt;&gt;而不是Func&lt;T, bool&gt;。 还需要考虑如何将动态构建的表达式应用到IQueryable上,使用Where方法,并确保整个过程不会导致过早的数据加载,保持查询的延迟执行特性。此外,处理不同数据类型(如字符串包含、数值比较)可能需要不同的表达式方法,比如使用string.Contains方法。 最后,应该提醒用户注意表达式树的不可变性,每次修改都需要创建新实例,以及参数一致性的问题。可能还需要提到第三方库如System.Linq.Dynamic.Core来简化复杂查询的构建。&lt;/think&gt;在C#中使用`IQueryable`进行动态查询的核心在于**通过表达式树(Expression Trees)动态构建查询条件**,而不是硬编码Lambda表达式。以下是实现步骤和关键方法: --- ### 一、基础原理 1. **`IQueryable`与表达式树的关系** `IQueryable`的扩展方法(如`Where`)接收`Expression&lt;Func&lt;T, bool&gt;&gt;`类型的参数,而非直接委托。这种表达式树结构允许LINQ提供程序(如Entity Framework)将其转换为目标查询语言(如SQL),实现延迟执行[^2]。 2. **动态构建的核心** 通过`System.Linq.Expressions`命名空间中的类(如`ParameterExpression`、`BinaryExpression`)动态生成表达式树节点,最终组合成完整的Lambda表达式。 --- ### 二、实现步骤(以动态过滤为例) #### 场景:根据属性名和值动态生成`Where`条件 ```csharp public static IQueryable&lt;T&gt; DynamicWhere&lt;T&gt;( this IQueryable&lt;T&gt; query, string propertyName, object value) { // 1. 构建参数表达式 p =&gt; p.Property var parameter = Expression.Parameter(typeof(T), &quot;p&quot;); // 2. 构建属性访问表达式 p.PropertyName var property = Expression.Property(parameter, propertyName); // 3. 构建常量表达式 value var constant = Expression.Constant(value); // 4. 构建相等比较表达式 p.Property == value var body = Expression.Equal(property, constant); // 5. 组合成Lambda表达式 var lambda = Expression.Lambda&lt;Func&lt;T, bool&gt;&gt;(body, parameter); // 6. 应用Where条件 return query.Where(lambda); } ``` **使用示例**: ```csharp var users = dbContext.Users; var filtered = users.DynamicWhere(&quot;Age&quot;, 25).ToList(); // 生成 WHERE Age = 25 ``` --- ### 三、进阶:动态拼接多条件 ```csharp public static Expression&lt;Func&lt;T, bool&gt;&gt; BuildPredicate&lt;T&gt;( string propertyName, object value, Operator op = Operator.Equal) { var parameter = Expression.Parameter(typeof(T), &quot;p&quot;); var property = Expression.Property(parameter, propertyName); var constant = Expression.Constant(value); Expression body; switch (op) { case Operator.Equal: body = Expression.Equal(property, constant); break; case Operator.Contains: var method = typeof(string).GetMethod(&quot;Contains&quot;, new[] { typeof(string) }); body = Expression.Call(property, method, constant); break; // 扩展其他运算符... } return Expression.Lambda&lt;Func&lt;T, bool&gt;&gt;(body, parameter); } // 动态组合多个条件 var predicate1 = BuildPredicate&lt;User&gt;(&quot;Name&quot;, &quot;John&quot;, Operator.Contains); var predicate2 = BuildPredicate&lt;User&gt;(&quot;Age&quot;, 20, Operator.GreaterThan); var finalPredicate = predicate1.And(predicate2); // 需实现And扩展方法 var result = dbContext.Users.Where(finalPredicate); ``` --- ### 四、关键注意事项 1. **类型兼容性** 确保属性类型与值类型匹配(如`int`属性不可与字符串比较),必要时进行类型转换: ```csharp var convertedValue = Convert.ChangeType(value, property.PropertyType); var constant = Expression.Constant(convertedValue); ``` 2. **表达式不可变性** 每次修改表达式树需创建新实例(如通过`Expression.AndAlso`组合条件)。 3. **参数一致性** 所有子表达式必须共享同一个`ParameterExpression`,否则会抛出参数不匹配异常[^3]。 --- ### 五、优化与扩展 - **使用第三方库** 复杂场景可引入`System.Linq.Dynamic.Core`库,直接解析字符串条件: ```csharp var query = dbContext.Users.Where(&quot;Age &gt; 25 &amp;&amp; Name.Contains(\&quot;A\&quot;)&quot;); ``` - **动态排序** 类似原理可扩展`OrderBy`动态排序,通过`Expression.Property`和`Expression.Lambda`生成排序表达式。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值