Odata在调用Contains时翻译Linq表达式时出错

1 c# asp.net odata

是否可以使用ASP.NET Web APi OData进行类似的操作:

List<string> customersTitles = Odata.OrdersService.Select(o=>o.CustomerTitle).Distinct().ToList();

List<Customer> customers = Odata.CustomerService.Where(m => customersTitles .Contains(m.CustomerTitle))
Run Code Online (Sandbox Code Playgroud)

得到错误:

将Linq表达式转换为URI时出错:表达式值(System.Collections.Generic.List`1 [System.String]).不支持包含([10007] .CustomerTitle).}

API:

public class CustomerController : EntitySetController<Customer, int>
{

    [Queryable]
    public override IQueryable<Customer> Get()
    {
        Expression filter = this.QueryOptions.Filter.ToExpression<Customer>();
        return db.Query<Customer>(filter as Expression<Func<Customer, bool>>);
    }
}
Run Code Online (Sandbox Code Playgroud)

Raj*_*dar 6

由于客户端存在的字符串列表不是服务器端资源,因此不支持通过URI构造Contains构造.

Linq2Sql Provider具有Contains的固有转换,它被转换为SQL的IN子句.

使用OData,不支持此类转换.您需要构建的是使用所有Title值的where子句的扩展查询列表:

因为这不起作用:

List<Customer> customers = Odata.CustomerService.Where(m => customersTitles .Contains(m.CustomerTitle))
Run Code Online (Sandbox Code Playgroud)

扩展的查询选项可帮助我们构建如下查询:

List<Customer> customers = Odata.CustomerService.Where(m => m.CustomerTitle == customerTitles[0] || m.CustomerTitle == customerTitles[1]); // and so on
Run Code Online (Sandbox Code Playgroud)

以下是过滤器构建的代码:

var titleFilterList = customerTitles.Select(title => String.Format("(CustomerTitle eq {0})", title));
var titleFilter = String.Join(" or ", titleFilterList);
var customers = Odata.CustomerService.AddQueryOption("$filter", titleFilter).Execute().ToList(); // you may have to cast this.
Run Code Online (Sandbox Code Playgroud)

还有另一种选择,可以使用一种很好的扩展方法以及构建基于动态表达式的谓词,以强类型的方式执行相同的操作.按照此处的步骤操作:

http://blogs.msdn.com/b/phaniraj/archive/2008/07/17/set-based-operations-in-ado-net-data-services.aspx