Neo Neo - 1 year ago 127
C# Question

Creating dynamic linq expression OData for multiple conditions for filter Contains?

For a single

Contains
filter condition in Odata I tried the following:

var customerData = await myclient.For<Customer>()
.Filter(x => x.Name.Contains("john"))
.FindEntriesAsync();


How can I use multiple
Contains
filters?

For example:

var customerData = await myclient.For<Customer>()
.Filter(x => x.Name.Contains("john") || x.Address.Contains("india"))
.FindEntriesAsync();


I tried with query expression using this code.

But, how do I pass filter expression inside 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();


I want to use
deleg
expression and pass to Odata.

var customerData = await myclient.For<Customer>()
.Filter(deleg.ToString())
.FindEntriesAsync();


I'm unable to execute the above statement.

Answer Source

First, Simple.OData.Client has its own LINQ expression parser, so everything that comes to Filter clause is sent to its custom parser that is far more limited than the one built into C# (aka LINQ-to-objects). And it's limited for good reasons, because it can't provide more than provided by OData protocol.

So expressions like Filter(deleg.ToString()) will not work, you will have to write the explicit expression.

Second, you can stack multiple Filter clauses but they will be combined using "AND" operator. And you need "OR".

Third, the epxression that you wrote (x => x.Name.Contains("john") || x.Address.Contains("india")) is a supported expression and should work.

If you must incrementally build Filter clause from a set of expressions then the only way to achive it using current version of Simple.OData.Client is to send a string to Filter, and that string can be built incrementally. You can even generate individal parts using Simple.OData.Client method GetCommandTextAsync(), then extract filter parts from them and concatenate. I know, it's not elegant.

UPDATE: I just pushed the version 4.12 that exposes public constructor for ODataExpression. So you can do things like these:

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();
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download