简体   繁体   English

在IEnumerable上使用&#39;Any&#39; <string> 在OData LINQ查询中

[英]Using 'Any' on IEnumerable<string> in OData LINQ query

I am using Microsoft.Data.Odata (5.6) to run following query: 我使用Microsoft.Data.Odata (5.6)运行以下查询:

IEnumerable<Service> services = context.Services.Expand(ServiceQueryExpansion)
    .Where(c =>
        (serviceNames.Any(s => s.Equals(
            c.ServiceName, StringComparison.OrdinalIgnoreCase))))

serviceNames is IEnumerable of string serviceNames是IEnumerable的字符串

I get following error while trying above query: 尝试上述查询时出现以下错误:

Error translating Linq expression to URI: The source parameter for the 'Any' method has to be either a navigation or a collection property.

How do I resolve this? 我该如何解决这个问题?

I know it is fun and exciting (sarcasm) but you can dynamically build your Where expression like this: 我知道这很有趣也很令人兴奋(讽刺)但你可以像这样动态构建你的Where表达式:

var serviceNames = new string[] { "SERVICE1","SERVICE2"};

Expression<Func<Service,bool>> inList = v => false;
var parameter = inList.Parameters[0];
var propertyExpression = Expression.Property(parameter,"ServiceName");

foreach (var serviceName in serviceNames)
{
   var body = inList.Body;
   var constantExpression = Expression.Constant(serviceName);
   var equalityExpression = Expression.Equal(propertyExpression,constantExpression);

   body = Expression.OrElse(body,equalityExpression);

   inList = Expression.Lambda<Func<Service, bool>>(body, parameter);
}

IEnumerable<Service> services = context.Services.Expand(ServiceQueryExpansion)
    .Where(inList);

This method builds a custom where clause from your list which will resemble (v => v.ServiceName == "Service1" || v.ServiceName == "Service2" || v.ServiceName == "Service3") 此方法从列表中构建一个自定义where子句,它类似于(v => v.ServiceName ==“Service1”|| v.ServiceName ==“Service2”|| v.ServiceName ==“Service3”)

You could probably follow the directions from my blog http://coding.grax.com/2013/07/filter-pattern-for-linq-query-filter.html to encapsulate this logic into a custom "WhereContains(yourListHere)" custom filter extension method. 您可以按照我的博客http://coding.grax.com/2013/07/filter-pattern-for-linq-query-filter.html中的说明将此逻辑封装到自定义“WhereContains(yourListHere)”自定义中过滤扩展方法。

You could write: 你可以写:

var services = context.Services.Expand(ServiceQueryExpansion).AsEnumerable()
      .Where(c => serviceNames.Contains(c.ServiceName));

But it will download entire Services collection. 但它将下载整个服务集合。 Or: 要么:

var services = serviceNames.SelectMany(s=>
     context.Services.Expand(ServiceQueryExpansion).Where(c=> c.ServicaName == s));

That will create N requests. 这将创建N个请求。

I don't know any better way to do this in Linq to OData. 我不知道在Linq到OData的任何更好的方法。

What I did was apply the filter that I could, then to list and then make another filter once you have your results locally. 我所做的是应用我可以使用的过滤器,然后列出,然后在本地获得结果后再制作另一个过滤器。

var services = context.Services.Expand(ServiceQueryExpansion).ToList();
services = services.Where(s => serviceNames.Any(n => n.ServiceName.Equals(s, StringComparison.OrdinalIgnoreCase)));

This is not the best option if you have several records that you don't need to get accross the network. 如果您有多条记录不需要通过网络,这不是最佳选择。

Another option is to create a Data Service Operation. 另一种选择是创建数据服务操作。

[WebGet]
public IQueryable<Service> GetServicesByServiceName(string serviceNames)
{
    var serviceNamesArray = serviceNames.Split(',');
    var ctx = YourContext();
    return ctx.Services.Include("ServiceQueryExpansion").Where(s => serviceNamesArrays.Any(n => s.ServiceName.Equals(n, StringComparison.OrdinalIgnoreCase))).AsQueryable();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM