2010-03-11 91 views
1

我看了一下this答案,它部分解決了我的問題。Lambda和嵌套對象

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

鑑於我有一個對象;

Product 
    string code 
    List<suitability> items 

然後我有這個對象;

Suitability 
    key 
    value 

每個產品具有可變數量的[項目],並且每個產品的關鍵/值對各不相同。

當搜索時,我給出了一個適宜性對象列表。我現在需要搜索包含(全部)所提供的適用對象的所有產品。

因此,例如,產品可能具有dental = true和therapies = true。

我可能會收到所有牙科=真,治療=假的產品的請求。

回答

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()); 

UPDATE:下面有我已經測試使用一個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 2010-03-11 02:19:58

+0

@griegs add .Compile()將Func從表達式'predicate'中取出...我更新了我的答案。 – 2010-03-11 03:05:48

+0

我改變了主意並選擇了這個作爲首選答案。作品感謝你。我仍然必須同意@Aaronaught使用EAV模型的方法並不理想,但是當您沒有其它選擇時... – griegs 2010-03-11 03:42:38

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; 

這只是不容易寫或有效的查詢上,實際上有dentaltherapies性質,而不是嵌套屬性的Product類。

如果你需要查詢上項目的數量會發生變化,那麼最簡單的方法來處理這是鏈接在一起的過濾器:

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

@Aarounaught,謝謝你,但我不能像你一樣編碼每一行。我可能會給出2個項目或10個。關於方法(EAV),您會建議什麼模型,每個產品的附加項目數量可變? – griegs 2010-03-11 01:48:04

+0

@griegs:爲動態數量的項目添加了一個版本。至於我會建議的 - 我會建議沒有一個設計,每個產品可以有任意的屬性集。這種設計是反模式,有時可能是必要的,但通常是模糊要求和期望通過最終用戶定製降低維護成本的結果。要知道,由於諸如此類的諸多問題,它實際上會提高TCO(另一個問題是屬性是弱類型的 - 如果要分類會發生什麼?);更好地修復模糊的需求。 – Aaronaught 2010-03-11 01:57:43

+0

我聽到你說過這個問題,但老闆指出我們需要一種方法來改變與產品相關的物品數量,以便每月適應業務的變化。 – griegs 2010-03-11 02:09:57