什么时候应该使用IEnumerable和IQueryable?

如何解决什么时候应该使用IEnumerable和IQueryable?

我已经尝试寻找差异很多次,并且有多个答案。

一个常见的区别是IEnumerable从内存中过滤数据,而IQueryable在服务器端进行数据过滤。

这到底是什么意思?

在内存数据上进行过滤还不是服务器端的事情吗?

我试图在多个地方寻找它们的用途,但是我无法用简单的文字找到它。

谢谢。

解决方法

IEnumerable<T>代表具有获得一系列结果所需的所有信息的事物。但是,它没有公开有关序列产生方式的信息。

IQueryable<T> expression tree的形式在Expression属性处公开有关如何构建序列的信息。然后,可以轻松地将此信息映射到一组不同的指令。

如果您在Enumerable.Where上调用IEnumerable<T>,则意味着传入的是已编译的方法Func<T,bool>,该方法不易解析和翻译;不可避免地,唯一的解决方法是将所有对象从服务器/提供者/数据源加载到内存中,并将编译后的方法应用于每个对象。

如果您在Queryable.Where上调用IQueryable<T>,则会传入一个表示不同代码操作的对象-Expression<Func<T,bool>>。例如:

IQueryable<Person> qry = /* ... */;
qry = qry.Where(x => x.LastName.StartsWith("A"));

编译器将x => x.LastName.StartsWith("A")转换为代表其各个部分的对象:

Lambda expression,returning a `bool`
    with an `x` parameter of type `Person`
    Call the `StartsWith` method,passing in a constant string `"A"`,on
        Result of the `LastName` property,of
            the `x` element

更多,调用Queryable.Where本身也会修改基础的表达式树:

Call to Queryable.Where,passing in
    The object at `qry`,and
    The previous lambda expression (see above)

枚举查询时(通过foreach或对ToList的调用或类似的方式),信息将被映射为另一种形式,例如SQL:

SELECT *
FROM Persons
WHERE LastName LIKE N'A%'

或网络请求:

http://example.com/Person?lastname[0]=a

如果可以使用构造函数以及对象和集合初始化程序构造表达式树,则调用Queryable.Where之后的最终表达式树看起来类似于此对象图:

var x = new ParameterExpression {
    Type = typeof(Person),Name = "x"
};

new MethodCallExpression {
    Type = typeof(IQueryable<Person>),Arguments = new ReadOnlyCollection<Expression> {
        new ConstantExpression {
            Type = typeof(EnumerableQuery<Person>)
        },new UnaryExpression {
            NodeType = ExpressionType.Quote,Type = typeof(Expression<Func<Person,bool>>),Operand = new Expression<Func<Person,bool>> {
                NodeType = ExpressionType.Lambda,Type = typeof(Func<Person,bool>),Parameters = new ReadOnlyCollection<ParameterExpression> {
                    x
                },Body = new MethodCallExpression {
                    Type = typeof(bool),Object = new MemberExpression {
                        Type = typeof(string),Expression = x,Member = typeof(Person).GetProperty("LastName")
                    },Arguments = new ReadOnlyCollection<Expression> {
                        new ConstantExpression {
                            Type = typeof(string),Value = "A"
                        }
                    },Method = typeof(string).GetMethod("StartsWith",new[] { typeof(string) })
                },ReturnType = typeof(bool)
            }
        }
    },Method = typeof(Queryable).GetMethod("Where",new[] { typeof(IQueryable<Person>),typeof(Expression<Func<Person,bool>>) })
}

(注意。这是使用ExpressionTreeToString library编写的。免责声明:我是作者。)

,

一个常见的区别是,IEnumerable从内存中过滤数据,而IQuerable在服务器端进行过滤

是的,一切都在服务器中进行。但是在上面的句子中,import concurrent.futures import requests import functools def get_info(session,symbol): """ r = session.get('https://somewebsite.com?symbol=' + symbol) return r.text """ return 'symbol answer: ' + symbol symbols = ['abc','def','ghi','jkl'] NUMBER_THREADS = min(30,len(symbols)) with requests.Session() as session: get_info_with_session = functools.partial(get_info,session) # this will be the first argument with concurrent.futures.ThreadPoolExecutor(max_workers=NUMBER_THREADS) as executor: results = executor.map(get_info_with_session,symbols) for result in results: print(result) 的意思是server side,而不是运行.NET应用程序的服务器。因此,主要思想是可以将IQueryable转换为将在SQL Server中执行的SQL脚本,与将数据从SQL Server导入应用程序相比,通常可以带来显着的性能提升内存,然后在内存中执行查询。

,

Zev Spitz已经很好地说明了这种差异,但是我想补充一个极端情况下发生的事例,以突出差异。

假设您的数据在一台服务器上,而应用程序在另一台服务器上运行。这些通过互联网连接。
假设您的数据中有一个表,其中有100万行,并且您想要一个具有给定ID(即id)的表。
忽略连接的精确程度,让变量Table作为代码中数据的表示形式。

现在,我们可以通过请求appsettings.{environment}.json来获得所需的行。

如果Table是一个IQueryable,则将其转换为对Table的那一行请求,该请求将从将数据存储在运行应用程序的服务器的内存中的服务器返回。

另一方面,如果我们将其视为IEnumerable,例如,将其作为<PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp3.1</TargetFramework> <RootNamespace>ConsoleApplication3</RootNamespace> <AssemblyName>ConsoleApplication3</AssemblyName> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.7" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="3.1.7" /> </ItemGroup> <ItemGroup> <None Update="appsettings.Development.json"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> <None Update="appsettings.json"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> </ItemGroup> 进行处理,则该请求将变为对表所有行的请求,然后将其转移到运行应用程序的服务器上的内存。只有在通过互联网传输了所有这100万行之后,应用程序才会对数据进行排序并挑选出您真正想要的行。

,

不能100%确定,但是我认为这意味着使用IQueryable,在我们正在BE中使用EF并使用SQLike as DB的示例中,其中编写的任何Linq过程都将在SQL和发送到数据库,它将详细说明此类sql代码,然后返回结果。

当IEnumelable缺少此功能时,例如,如果将整个实体转换为IEnumerable,则将始终在BE内详细说明所有过滤器。

我希望我是对的,我已经很清楚了, 会议愉快

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-