2015-10-21 2 views
1

Для одного состояния Contains фильтра в OData Я попробовал следующее:Создание динамического выражения linq OData для множества условий для фильтра Содержит?

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

ли вы попробовать AddQueryOption https://msdn.microsoft.com/en-us/library/dd673933.aspx – aguetat

+0

мне это нужно для OData я попробовал некоторые и редактировал свой вопрос пожалуйста, проверьте – Neo

ответ

1

Во-первых, Simple.OData.Client имеет свой собственный LINQ выражение парсер, так что все, что приходит в фильтр пункт отправляется его пользовательского анализатора, гораздо более ограниченным, чем один встроенный в C# (также известный как LINQ-to-objects). И это ограничено по уважительным причинам, потому что оно не может обеспечить больше, чем предусмотрено протоколом OData.

Так что выражения типа Filter deleg.ToString() не будут работать, вам придется написать явное выражение.

Во-вторых, вы можете складывать несколько предложений фильтра, но они будут объединены с помощью оператора «И». И вам нужно «ИЛИ».

В-третьих, выражение, которое вы написали (x => x.Name.Contains("john") || x.Address.Contains("india")), является поддерживаемым выражением и должно работать.

Если вы должны поэтапно построить предложение Filter из набора выражений, то единственный способ получить его с использованием текущей версии Simple.OData.Client - это отправить строку в Filter, и эта строка может быть построена постепенно. Вы можете даже генерировать отдельные части, используя метод Simple.OData.ClientGetCommandTextAsync(), затем извлекать из них части фильтра и объединять. Я знаю, это не изящно.

UPDATE: Я просто нажал версию 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(); 
+1

Ну, на самом деле здесь можно что-то сделать. Internally Simple.OData.Client использует класс ODataExpression, он просто не предоставляет публичный метод для преобразования выражения LINQ в ODataExpression. Я подумаю о возможности его открыть. вверх. –

+0

спасибо большое, это будет здорово, если какой-нибудь фрагмент кода будет предоставлен после того, как вы его опубликуете – Neo

+1

@Neo, посмотрите версию 4.12, которая реализует то, что вам нужно, см. Мой обновленный ответ. –

1

У меня нет вашего datamodel, поэтому я использовал канал Northwind OData для создания решения для вас.

Что это такое, итерация по словарю, который определяет поисковик и свойство, которое нужно искать.

Затем мы создаем предикат и перебираем каждый из этих kvp. Наконец, мы возвращаем функцию лямбды из этого. Думайте об этом как predicatebuilder в цикле:

/*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(); 

Ouput: enter image description here

Единственное, что осталось для вашей сделать, это заменить Category против вашего целевого типа. Если это позволит время, я оберну его общим методом и добавлю его к этому ответу.

Linqpad source

// EDIT: Heres статический метод для построения выражения. Вам нужно только указать 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(); 
+0

фантастически, это будет отличная помощь, но я использую простой odata. Я также отредактировал свой вопрос и добавил общий метод, заданный в codeproject, но он специфичен для linq, не работающего над выражением Odata, пожалуйста, проверьте это, также если у вас есть время. – Neo

+0

Я могу передать 'предикат' внутри' var customerData = await myclient.For () .Filter (predicate.ToString()) .FindEntriesAsync(); '?? – Neo

+0

'Customer.Where (lambda) .Dump();' не содержит определения для 'Where' – Neo

Смежные вопросы