Reputation: 165
I am using Microsoft.Data.Odata
(5.6) to run following query:
IEnumerable<Service> services = context.Services.Expand(ServiceQueryExpansion)
.Where(c =>
(serviceNames.Any(s => s.Equals(
c.ServiceName, StringComparison.OrdinalIgnoreCase))))
serviceNames is IEnumerable of string
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?
Upvotes: 1
Views: 2694
Reputation: 4069
I know it is fun and exciting (sarcasm) but you can dynamically build your Where expression like this:
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")
You could probably follow the directions from my blog https://secureapplicationlifestyle.com/2013/07/filter-pattern-for-linq-query-filter.html to encapsulate this logic into a custom "WhereContains(yourListHere)" custom filter extension method.
Upvotes: 3
Reputation: 151
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();
}
Upvotes: 0
Reputation: 1463
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.
I don't know any better way to do this in Linq to OData.
Upvotes: 0