Lambda和嵌套对象

时间:2010-03-11 01:35:34

标签: linq lambda

我看了一下this的答案,这部分是为了解决我的问题。

但是,我需要的是以下内容。

鉴于我有一个对象;

Product
  string code
  List<suitability> items

然后我有了这个对象;

Suitability
  key
  value

每个产品都有可变数量的[项目],键/值对因产品而异。

搜索时,我会得到一个Suitability对象列表。我现在需要搜索包含(所有)提供的适用性对象的所有产品。

例如,产品可能有牙齿=真,疗法=真。

我可能会收到所有牙齿= true且疗法=假的产品的请求。

2 个答案:

答案 0 :(得分: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;

在查询实际上具有Productdental属性而不是嵌套属性的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 :(得分: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());

更新:下面是我测试的一些示例代码,它使用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());