首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在运行时使用属性名称和类型查询IQueryable

在运行时使用属性名称和类型查询IQueryable
EN

Stack Overflow用户
提问于 2019-06-29 00:18:48
回答 1查看 280关注 0票数 0

我需要在运行时知道属性名称和类型的情况下进行查询。我在IEnumerable<>上使用了反射,但是会因为这个而出现性能问题吗?

我想知道是否有更好的方法使用IQueryable<>来实现这一点?我研究了一下Expressions,但我不太确定该怎么做。

编辑:

目前这似乎不是一个性能问题,但我还没有在非常大的工作负载下进行测试。

我需要在运行时已知的多个不同类型的字段中进行搜索。

代码语言:javascript
复制
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();

和这个辅助方法:

代码语言:javascript
复制
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;
}

我不知道在这种特殊情况下,是否有更好的方法来做到这一点。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 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中进行计算。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56810209

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档