2014-10-21 7 views
0

Ниже я нашел фрагмент кода в одном из наших проектов. Я застрял в течение двух дней :-(пытаясь понять Совокупные & LinQKit Expand.Преобразование LINQ to normal Foreach

Можете ли вы помочь в преобразовании ниже LINQ к нормальной работе Еогеасп?

public Expression<Func<Purchase, bool>> forTarget(List<string> idList) 
{ 
    Expression<Func<Purchase, string>> fc = p => p.ClientId; 
    Expression<Func<Purchase, bool>> predicate = m => false; 

    return idList.Aggregate(predicate, (p, id) => p.Or(m => fc.Invoke(m) == id), p => p.Expand()); 
} 

internal class Purchase 
{ 
    public int Price { get; set; } 
    public string Description { get; set; } 
    public string ClientId { get; set; } 
} 

public class Client 
{ 
    public string Id { get; set; } 
} 

или по крайней мере, любой указатель на то, что это выражение LINQ делает в списке, было бы очень полезно.

return idList.Aggregate(predicate, 
     (p, id) => p.Or(m => fc.Invoke(m) == id), 
     p => p.Expand()); 

ответ

2

функция перебирает коллекции элементов и создает предикат, добавив or для каждого значения ClientId.

В ранних версиях Linq2SQL не было никакой поддержки для метода Contains так что вы не были в состоянии выполнить запрос следующим образом:

IEnumerable<Purchase> purchases = LoadSelectedItems(); 
var clientIds = purchases.Select(p => p.ClientId).ToArray(); 
var results = db.Clients.Where(c => clientIds.Contains(c.Id)); // Did not work. 

Обойти эту проблему, чтобы создать предикат, который будет проверять используя or, соответствует ли Id конкретному значению. Таким образом, для приведенного выше примера, если clientIds = {1, 2, 3} оговорка Where будет записана как:

var results = db.Clients.Where(c => c.Id == 1 || c.Id == 2 || c.Id == 3); 

Как вы можете видеть, этот вид заявления не очень элегантно, становится нечитаемым, когда совокупность значений для проверки против (т.е. clientIds) очень большой и, самое главное, вы не можете знать априори, какие значения будут для них жестко кодировать. Итак, чтобы преодолеть эту проблему, решение состоит в том, чтобы обобщить вышеуказанный предикат с переменным набором значений. И это делается просто с помощью следующего алгоритма:

  1. Создать Expression, которая возвращает false; если мы вернем true, компилятор проведет короткую замыкание оценки (потому что мы используем or) и вернем true для всех элементов;
  2. Для каждого элемента в коллекции значений добавьте предложение or со значением элемента.

Теперь, ваш пример может быть преобразован в Еогеасп таким образом:

// start with a predicate returning false 
// this is the seed of the Aggregate method 
Expression<Func<Purchase, bool>> predicate = m => false; 
// Now, iterate the collection and build the full predicate 
foreach(var id in idList) 
{ 
    // Build the predicate by invoking a function which returns the client id of the 
    // purchase and comparing it with the value of the current id from the idList 
    predicate = predicate.Or(item => item.ClientId == id); 
} 

Надеется, что это помогает.

+0

Спасибо! это действительно полезно. Любые указатели на LinQKit Expand(), пожалуйста? – Abhijeet

+0

@Abhijeet, к сожалению, не могу сказать ... 'Expand()' метод пытается «оптимизировать» лямбда-выражение, чтобы он мог быть эффективно преобразован в SQL-запрос. – RePierre

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