OData IEnumerable 或 IQueryable

Posted

技术标签:

【中文标题】OData IEnumerable 或 IQueryable【英文标题】:OData IEnumerable or IQueryable 【发布时间】:2021-02-24 12:06:19 【问题描述】:

我对 OData v3/v4 还是很陌生,我使用 Visual Studio 中的 OData Connect 服务从 OData 服务器获取数据。现在我的问题是什么是获取数据的最佳、最快的方法,然后使用自己的集合进行验证?

例如,我们有一个Microsoft.OData.Client.DataServiceQuery 类型为Employee,我们想从服务器获取所有员工并将其与我们的本地数据集(例如来自另一个CRM 系统的List(Of Employee))进行比较

要从 OData 服务获取数据,我们必须设置 DataServiceQuery,例如:获取所有员工的简单方法是 DataServiceQuery.GetAllPages,这会返回一个 IEnumerable(Of Employee),我们可以在其上调用 .ToList 函数。在此之后,我们可以使用 LINQ 和/或 LAMBDA 在两个列表之间进行每次比较和更新集合。

但是现在如果我使用DataServiceQuery.Take(Number) 更改方法,那么它会返回一个IQueryable(Of Employee),我们也可以在其上调用.ToList 或者IQueryable 是否不必要?

所以我的问题是从 OData v4 服务器获取所有数据然后将其填充到内存中然后使用 LINQ 和/或 LAMBDA 进行比较的最佳方法是什么?

【问题讨论】:

如果您只需要迭代一次数据(与其他列表比较就足够了),则使用ToList 效率低下,因为除了数据服务的缓冲区之外,您还必须为所有数据分配缓冲区用途。如果您受到限制并且无法更改比较您的列表并将一个列表更改为IEnumerable<T> 的方法,或者不关心内存和性能,只需在两者上使用ToList 【参考方案1】:

实际上,您的两个解决方案都将做相同的事情,唯一的区别是,在这种情况下,通过使用.Take(),您正在编写一个查询,该查询将批处理来自服务器的数据,您可能更熟悉这被称为分页

在 OData 服务器逻辑中,IEnumerable 和 IQueryable 之间的区别很大,因为 IQueryable 被延迟直到您迭代查询,像 .ToList() 这样的调用将强制进行此迭代。

然而,在客户端,即使数据类型是 Linq IQueryable 类型,当您完成查询时,您只能迭代一次,@ 也是如此987654324@ 来自DataServiceQuery 的回复。

但是现在如果我通过使用 DataServiceQuery.Take(Number) 改变方法,那么它会返回一个 IQueryable(Of Employee),我们也可以在其上调用 .ToList 或者使用 IQueryable 是否不必要?

专门针对DataServiceQuery,鉴于我们只能迭代一次响应,作为一般模式,我们通常DO调用.Tolist()来强制接收来自服务器的响应,所以它很明显,这是我们的意图。

这不是必要与否的问题,而是有意下载数据一次,并将其存储在允许我们再次对其进行迭代的列表变量中。

IQueryable 响应允许您在将其发送到服务器之前构建过滤器、顺序和投影表达式,在 OData 术语中,这应该转换为 $filter$orderby$expand$select、@与 HTTP 请求一起发送的 987654333@ 和 $top 查询选项。如果您要应用其中任何一个,它会提高性能,但在这里看起来并不适用。

所以关于您的问题,因为您正在获取 所有 数据,DataServiceQuery 的这两种类型的响应之间没有性能差异。当您不想要 ALL 行时,一个事实开始发挥作用:

如果您使用Where()ApplyQueryOption().Take() 限制了记录的数量,那么由于有效负载将小于非限制查询,它将更快地返回,这完全是由于数据有效负载超过电线变小了。

如果您要调用 .ToList()然后 应用过滤或限制,则必须先下载整个集合,然后才能评估您的过滤器,因此您可以通过使用获得最佳性能IQueryable 并在您执行它之前应用过滤条件

再次,对于您的特定任务,因为它涉及迭代整个集合,这些都没有任何固有的优势。如果记录集很大,我会鼓励您使用批处理/分页来处理较小集中的记录,以免锁定服务器资源,并且 不会 耗尽内存来尝试在单个操作中反序列化整个结果集。


无论哪种方式运行这些类型的数据同步通常都是昂贵的过程,但是通过在客户端上执行此操作,您可能选择了效率最低的机制。

如果可以的话,这个任务应该在服务器端执行,这样可以减少一整圈的数据比较


如果无法在服务器上执行比较,那么也许您可以将比较公式化为IQueryable 表达式,只返回匹配或不匹配的结果,这就是IQueryable 的强大之处播放时,它会将表达式传递给服务器,直接在数据库中进行比较。

【讨论】:

以上是关于OData IEnumerable 或 IQueryable的主要内容,如果未能解决你的问题,请参考以下文章

可以使 OData 返回 CSV 或 URL 吗?

OData substringof或startswith返回所有项目

ReadOnlyCollection 或 IEnumerable 用于公开成员集合?

WebApi OData:$filter 'any' 或 'all' 查询不起作用

C# 列出 IList 或 IEnumerable 作为参数

EF4 complex Select():从业务层返回 IEnumerable 或 IEnumerable<MyCustomDto>?