Лямбда и вложенные объекты - PullRequest
1 голос
/ 11 марта 2010

Я посмотрел на этот ответ, и это частично относится к решению моей проблемы.

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

Учитывая, что у меня есть объект;

Product
  string code
  List<suitability> items

и тогда у меня есть этот объект;

Suitability
  key
  value

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

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

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

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

Ответы [ 2 ]

2 голосов
/ 11 марта 2010

Прежде всего, я хотел бы отметить, что пары ключ-значение (модель 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);
1 голос
/ 11 марта 2010

Используя 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());

ОБНОВЛЕНИЕ: Вот некоторый пример кода, который я тестировал, который работает с использованием 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());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...