First of all I'd like to point out that key-value pairs (AKA EAV model) are a poor choice for representing this kind of data, and this question is a perfect example of why - it's much, much harder to search for arbitrary collections of attributes than it is to search for specific properties.
Of course, it can still be done:
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;
It's just not as easy to write or efficient as querying on a Product
class that actually has dental
and therapies
properties as opposed to nested attributes.
If you the number of items you need to query on can change, then the easiest way to handle that is to chain together filters:
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
If you're looking for a more "functional" way to do it without chaining then:
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);