2013-08-29 37 views
1

我使用Microsoft.Data.Odata(5.6)來運行下面的查詢:使用 '任意' 上的IEnumerable <string>中的OData LINQ查詢

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

serviceNames是IEnumerable的字符串

試圖上面的查詢我獲得以下錯誤:

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

我該如何解決這個問題?

+0

@RowlandShaw從OP * serviceNames是IEnumerable的字符串* – CodingIntrigue

+0

@RowlandShaw的,我很抱歉,但OP實際上是國家這樣做'serviceNames是IEnumerable的string'的。此外,OP表示他們想在問題中使用同樣類型的「Any」。 –

+0

'services'是'IEnumerable '(如我們所見)。 'serviceNames',因爲OP聲稱他已經在範圍之外聲明爲'IEnumerable ' – CodingIntrigue

回答

0

你可以寫:

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

但它會下載整個服務集合。 或者:

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

,將創建N個請求。

我不知道有任何更好的方法在Linq中對OData做到這一點。

3

我知道這是有趣和令人興奮(諷刺),但你可以動態建立你在哪裏表達這樣的:

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); 

這種方法建立一個自定義的,其中從列表條款,將類似於(V => v .ServiceName ==「服務1」 || v.ServiceName ==「服務2」 || v.ServiceName ==「服務3」)

你也許可以遵循從我的博客http://coding.grax.com/2013/07/filter-pattern-for-linq-query-filter.html方向這個邏輯封裝到一個自定義「 WhereContains(yourListHere)「自定義過濾器的擴展方法。

+1

請注意結果表達式隨集合增長。在達到某個限制條件後(儘管可能非常高),這可能會崩潰。在一個巨大的''serviceNames''集合上進行測試,以確保它適用於您的情況。 –

0

我所做的是應用我可以的過濾器,然後列出並在本地獲得結果後再製作另一個過濾器。

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

如果您有幾條不需要跨網絡記錄的記錄,這不是最好的選擇。

另一種選擇是創建數據服務操作。

[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(); 
}