2010-03-11 5 views
1

Я взглянул на ответ this, и это частично зависит от решения моей проблемы.Лямбда и вложенные объекты

Однако мне нужно следующее.

У меня есть объект;

Product 
    string code 
    List<suitability> items 

, а затем у меня есть этот объект;

Suitability 
    key 
    value 

Каждый продукт имеет переменное количество [пунктов], а пары ключ/значение отличаются от продукта к продукту.

При поиске мне дается список объектов пригодности. Теперь мне нужно искать все продукты, содержащие (все) предоставленные объекты пригодности.

Так, например, продукт может иметь стоматологический = истинный и терапия = истина.

Я могу получить запрос на все продукты, имеющие dental = true и therapies = false.

ответ

1

Использование PredicateBuilder (от авторов LINQPad) вы можете создать запрос из набора условий не известно во время компиляции. Следующее должно быть достаточным:

var predicate = PredicateBuilder.True<Product>(); 

foreach (Suitability criteria in searchCriteria) 
{ 
    string tempKey = criteria.Key; 
    string tempValue = criteria.Value; 
    predicate = predicate.And(p => 
        p.Items.Any(s => s.Key == tempKey && s.Value == tempValue)); 
} 

return dataContext.Products.Where(predicate.Compile()); 

ОБНОВЛЕНИЕ: Heres некоторые примеры кода, которые я испытал, который работает используя IEnumerable в качестве источника, полученное множество productsResult содержит первый и второй продукты в products списке:

var searchCriteria = new List<Suitability>() 
    { 
     new Suitability() { Key="a", Value="b" }, 
     new Suitability() { Key="a", Value="c" } 
    }; 

var products = new List<Product>() 
    { 
     new Product() 
      { 
       Items = new List<Suitability>() { 
          new Suitability() { Key="a", Value="b" }, 
          new Suitability() { Key="a", Value="c" }} 
      }, 
     new Product() 
      { 
       Items = new List<Suitability>() { 
          new Suitability() { Key="a", Value="b" }, 
          new Suitability() { Key="a", Value="c" }, 
          new Suitability() { Key="b", Value="c" }} 
      }, 
     new Product() 
      { 
       Items = new List<Suitability>() { 
          new Suitability() { Key="c", Value="d" }} 
      } 
    }; 

    var predicate = PredicateBuilder.True<Product>(); 

    foreach (Suitability criteria in searchCriteria) 
    { 
     string tempKey = criteria.Key; 
     string tempValue = criteria.Value; 
     predicate = predicate.And(p => p.Items.Any(
         s => s.Key == tempKey && s.Value == tempValue)); 
    } 

    IEnumerable<Product> productsResult = products.Where(predicate.Compile()); 
+0

@Simon, я попытался реализовать это, но потом я вспомнил, что у меня нет datacontext, так как это не LINQ to SQL, и когда я применяю его к списку IEnumerable , я получаю сообщение об ошибке. Ошибка \t Аргументы типа для метода 'System.Linq.Enumerable.Where (System.Collections.Generic.IEnumerable , System.Func )' не может быть выведен из использования. Попробуйте явно указать аргументы типа. – griegs

+0

@griegs add .Compile(), чтобы получить Func из выражения «предикат» ... Я обновил свой ответ. –

+0

Я передумал и выбрал это как предпочтительный ответ. Работает, спасибо. Я все еще должен согласиться с @Aaronaught, что подход использования модели EAV не идеален, но когда у вас нет альтернативы ... – griegs

2

Прежде всего я хотел бы указать, что пары ключевого значения (модель AKA EAV) являются плохим выбором для представления данных такого типа, и этот вопрос является прекрасным примером того, почему - это намного сложнее для поиска произвольных коллекций атрибутов, чем для поиска конкретных свойств.

Конечно, это еще можно сделать:

var suitableProducts = 
    from p in products 
    where 
     p.Items.Any(s => s.Key == "dental" && s.Value == "true") && 
     p.Items.Any(s => s.Key == "therapies" && s.Value == "false") 
    select p; 

Это просто не так легко писать или эффективно, как запрос на Product класс, который на самом деле имеет dental и therapies свойства, в отличие от вложенных атрибутов.

Если количество элементов, которые нужно запрос на может измениться, то самый простой способ обработки этой цепи вместе фильтры:

var searchItems = ... 
var result = products; 
foreach (var searchItem in searchItems) 
{ 
    result = result.Where(p => 
     p.Items.Any(s => s.Key == searchItem.Key && 
         s.Value == searchItem.Value)); 
} 
// Do something with result 

Если вы ищете более «функциональный "способ сделать это без цепочки, то:

var suitabilityConditions = searchItems.Select(i => 
    (Predicate<Product>)(p => p.Items.Any(s => 
     s.Key == searchItem.Key && s.Value == searchItem.Value))); 
Predicate<Product> match = p => suitabilityConditions.All(c => c(p)); 
var suitableProducts = products.Where(match); 
+0

@ Не знаю, спасибо за это, но я не могу закодировать каждую строку, как у вас. Мне могут быть предоставлены 2 предмета или 10. Что касается подхода (EAV), какую модель вы бы предложили, где каждый продукт имеет переменное количество предметов, прикрепленных к нему? – griegs

+0

@griegs: Добавлена ​​версия для динамического количества элементов. Что касается того, что я хотел бы предложить, я бы предложил не иметь дизайн, где каждый продукт может иметь произвольные наборы атрибутов. Такие конструкции являются анти-шаблонами и иногда могут быть необходимы, но обычно являются результатом сочетания неопределенных требований и желания снизить затраты на обслуживание за счет настройки конечного пользователя.Знайте, что это на самом деле повысит TCO из-за множества проблем, подобных этому (другая проблема заключается в том, что атрибуты слабо типизированы - что произойдет, если вы хотите сортировать?); лучше исправить неопределенные требования. – Aaronaught

+0

Я слышал, что вы и это обсуждалось, но босс указал, что нам нужен способ изменить количество предметов, связанных с продуктом, для ежемесячного изменения настроений в бизнесе. – griegs

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