对于Odata中的单个Contains
过滤条件,我尝试了以下操作:
var customerData = await myclient.For<Customer>()
.Filter(x => x.Name.Contains("john"))
.FindEntriesAsync();
如何使用多个Contains
过滤器?
例如:
var customerData = await myclient.For<Customer>()
.Filter(x => x.Name.Contains("john") || x.Address.Contains("india"))
.FindEntriesAsync();
我使用此code尝试使用查询表达式。
但是,如何在Odata .Filter()
中传递过滤器表达式?
List<Filter> filter = new List<Filter>()
{
new Filter { PropertyName = "City" ,
Operation = Op .Equals, Value = "Mitrovice" },
new Filter { PropertyName = "Name" ,
Operation = Op .StartsWith, Value = "L" },
new Filter { PropertyName = "Salary" ,
Operation = Op .GreaterThan, Value = 9000.0 }
};
var deleg = ExpressionBuilder.GetExpression<Person>(filter).Compile();
我想使用deleg
表达式并传递给Odata。
var customerData = await myclient.For<Customer>()
.Filter(deleg.ToString())
.FindEntriesAsync();
我无法执行上述声明。
答案 0 :(得分:1)
我没有您的数据模型,因此我使用Northwind OData Feed为您构建解决方案。
这样做,迭代一个字典,它定义了一个searchterm和一个可以查看的属性。
然后我们构建一个谓词并迭代每个kvp。最后我们从中返回一个lambda函数。 把它想象成循环中的谓词构建者:
/*using http://services.odata.org/V3/Northwind/Northwind.svc/ */
//Define a set of KeyValueParis to search for
var keywords = new Dictionary<string, string> {
{"Beverages", "CategoryName"},
{"savory", "Description"},
{"meats", "Description"},
{"Condiments", "CategoryName"}
};
//Create the predicate and initialize it
Expression<Func<Category, bool>> predicate = x => false;
//Define the type
ParameterExpression parameterExp = Expression.Parameter(typeof(Category), "Category");
//Get the Contains method. reference: http://stackoverflow.com/questions/278684/how-do-i-create-an-expression-tree-to-represent-string-containsterm-in-c
MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
//Iterate over each kvp
foreach (var kvp in keywords)
{
var body = predicate.Body;
//set the property or field we are checking against
var memberExpr = Expression.PropertyOrField(parameterExp, kvp.Value);
var constExpr = Expression.Constant(kvp.Key, typeof(string));
var containsMethodExpr = Expression.Call(memberExpr, method, constExpr);
body = Expression.OrElse(body, containsMethodExpr);
predicate = Expression.Lambda<Func<Category, bool>>(body, parameterExp);
}
Categories.Where (predicate).Dump();
您唯一要做的就是将Category
替换为您的目标类型。如果时间允许,我会用通用方法将其包装起来并将其添加到此答案中。
//编辑:这是一个构建表达式的静态方法。您只需要通过搜索字词提供Dictionary<string,string>
。
static Expression<Func<T, bool>> BuildExpression<T>(Dictionary<string, string> searchTerms)
{
//Create the predicate and initialize it
Expression<Func<T, bool>> predicate = x => false;
//Define the type
ParameterExpression parameterExp = Expression.Parameter(typeof(T), "type");
//Get the Contains method. reference: http://stackoverflow.com/questions/278684/how-do-i-create-an-expression-tree-to-represent-string-containsterm-in-c
MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
//Iterate over each kvp
foreach (var kvp in searchTerms)
{
var body = predicate.Body;
//set the property or field we are checking against
var memberExpr = Expression.PropertyOrField(parameterExp, kvp.Value);
var constExpr = Expression.Constant(kvp.Key, typeof(string));
var containsMethodExpr = Expression.Call(memberExpr, method, constExpr);
body = Expression.OrElse(body, containsMethodExpr);
predicate = Expression.Lambda<Func<T, bool>>(body, parameterExp);
}
return predicate;
}
用法:
var lambda = BuildExpression<Category>(keywords);
Categories.Where(lambda).Dump();
答案 1 :(得分:1)
首先,Simple.OData.Client有自己的LINQ表达式解析器,因此Filter子句的所有内容都被发送到其自定义解析器,该解析器比C#内置的解析器(又名LINQ-to-objects)更受限制。并且它有充分理由限制,因为它不能提供超过OData协议提供的内容。
因此像Filter deleg.ToString()
这样的表达式将不起作用,您必须编写显式表达式。
其次,您可以堆叠多个Filter子句,但它们将使用&#34; AND&#34;进行组合。运营商。你需要&#34;或&#34;。
第三,您编写的(x => x.Name.Contains("john") || x.Address.Contains("india"))
表达式是受支持的表达式,应该可以正常工作。
如果必须从一组表达式逐步构建Filter子句,那么使用当前版本的Simple.OData.Client
实现它的唯一方法是将字符串发送到Filter,并且可以逐步构建该字符串。您甚至可以使用Simple.OData.Client
方法GetCommandTextAsync()
生成单个零件,然后从中提取过滤器零件并进行连接。我知道,它并不优雅。
更新:我刚推送了暴露公共构造函数的版本4.12,用于ODataExpression。所以你可以做这些事情:
Expression<Predicate<Product>> condition1 = x => x.ProductName == "Chai";
Expression<Func<Product, bool>> condition2 = x => x.ProductID == 1;
var filter = new ODataExpression(condition1);
filter = filter || new ODataExpression(condition2);
var result = await client.For<Product>.Filter(filter).FindEntriesAsync();
or
var filter = new ODataExpression<Product>(x => x.ProductName == "Chai");
filter = filter || new ODataExpression<Product>(x => x.ProductID == 1);
var result = await client.For<Product>.Filter(filter).FindEntriesAsync();