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 substringof或startswith返回所有项目
ReadOnlyCollection 或 IEnumerable 用于公开成员集合?
WebApi OData:$filter 'any' 或 'all' 查询不起作用
C# 列出 IList 或 IEnumerable 作为参数
EF4 complex Select():从业务层返回 IEnumerable 或 IEnumerable<MyCustomDto>?