我需要在运行时知道属性名称和类型的情况下进行查询。我在IEnumerable<>
上使用了反射,但是会因为这个而出现性能问题吗?
我想知道是否有更好的方法使用IQueryable<>
来实现这一点?我研究了一下Expressions
,但我不太确定该怎么做。
编辑:
目前这似乎不是一个性能问题,但我还没有在非常大的工作负载下进行测试。
我需要在运行时已知的多个不同类型的字段中进行搜索。
var cosmosClient = new DocumentClient(new Uri(cosmosDBEndpointUrl), cosmosDBAuthorizationKey);
var feedOptions = new FeedOptions { MaxItemCount = -1, EnableCrossPartitionQuery = true };
var objects = cosmosClient.CreateDocumentQuery<MyObject>(collectionLink, feedOptions).AsEnumerable();
if (!string.IsNullOrEmpty(searchQuery))
{
var predicate = PredicateBuilder.New<MyObject>();
foreach (var fieldToSearch in fieldsToSearch)
{
predicate = predicate.Or(x => x.GetPropertyValue(fieldToSearch).CheckDateTime().ToString()
.Contains(searchQuery, StringComparison.InvariantCultureIgnoreCase));
objects = objects.Where(predicate);
}
}
objects = objects.Skip(index)
.Take(pageSize);
return objects.ToList();
和这个辅助方法:
public static object GetPropertyValue(this object obj, string propertyName)
{
foreach (var part in propertyName.Split('.'))
{
if (obj == null) { return null; }
Type type = obj.GetType();
PropertyInfo info = type.GetProperty(part, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
if (info == null) { return null; }
obj = info.GetValue(obj, null);
}
return obj;
}
我不知道在这种特殊情况下,是否有更好的方法来做到这一点。
发布于 2019-07-09 03:09:49
因此,在这种情况下,I do think you want IQueryable
而不是IEnumerable
。最容易记住的方法是IEnumerable
将所有数据加载到内存中,然后运行其余的LINQ查询,而IQueryable
尝试在源上运行过滤器,如果可以的话,它会将结果数据加载到内存中。您确实需要使用支持IQueryable
的对象关系映射,如LINQ to SQL或Entity Framework。在CosmosDB的情况下,SDK是建立在LINQ to SQL之上的。
通过使用IEnumerable
,您可以将来自Cosmos的所有数据加载到内存中,然后应用您的过滤器和分页。当您只有几条记录时,这很好,但是随着数据集的增长,您可能会想到这会成为一个大问题。通常,您希望在数据库中做尽可能多的工作,并且只返回最少的结果。这将远远超过使用反射来构建谓词的任何性能考虑因素。
IQueryable
最好的部分之一是它继承了IEnumerable
,所以任何使用IEnumerable
的东西都可以使用IQueryable
。你需要做的就是去掉你的AsEnumerable()
。
重要的是要注意,并不是所有的LINQ操作符都是自动支持的,一旦系统命中一个操作符,它就不能翻译,它就执行到目前为止的操作,并在内存中完成其余的操作。在文档中有一个CosmosDB的list of available operators。
对于您的查询,最大的问题将是,虽然您的Where()
子句受支持,但Skip()
和Take()
目前不受支持,这意味着每次执行此方法时,将从CosmosDB返回所有结果,然后将计算分页。
在SDK中有几种处理分页的方法。当前支持的方式是将FeedOptions
中的MaxItemCount
设置为您的页面大小。当前系统不使用Skip()
函数,而是使用连续标记。为了访问令牌,您可以使用AsDocumentQuery()
。由于您必须遍历每一页到下一页,因此缓存令牌可能非常有帮助-跳转起来很困难。
第二种选择是使用.Net SDK的v3。它目前处于预览阶段,但是是available on Nuget。几个月前,skip/take was enabled。在这种情况下,在调用ToList()
之前的所有内容都应该转换为SQL并在CosmosDB中进行计算。
https://stackoverflow.com/questions/56810209
复制相似问题