2015-06-19 68 views
1

我試圖解決以下LINQ查詢實體:EF LINQ - 返回包含整個集合

public JsonResult SearchNodesByTags(string[] tags) 
{  

    var nodes = _DbContext.Nodes. 
      Where(n => n.Tags.All(t => tags.Contains(t.DisplayName))) 
      .Select(n => new {n.NodeNativeId, n.NodeName, n.NodeClass.ClassName}) 
      .ToList(); 

    return Json(nodes); 
} 

該查詢返回了不與標籤相關聯的一個節點。我想要它做的是返回任何具有所有標籤的節點。

+0

你必須添加'n.Tags.Any()&& n.Tags.All(...'。這消除了沒有標籤的節點。如果'tags'變量中存在真正的標記,我不會看到查詢如何返回任何節點。 –

回答

2
.Where(n => n.Tags.All(t => tags.Contains(t.DisplayName))) 

這是目前構建的方式,你只會與Node S其中Node.Tags標籤在tags白名單,其中包括Node s的有一個名字落得沒有標籤。


你可能想在子集使用回答here

_DbContext.Nodes 
    .Where(n => !tags.Except(n.Tags.Select(t => t.DisplayName)).Any()) 
    .Select(... 
  • set1.Except(set2)包含set1元素不在set2
  • !set1.Except(set2).Any() == true如果set2包括set1每一個元素

編輯

有人指出,在評論中,使用除了可能產生問題的查詢,所以我想另一種選擇是從數據庫中獲取的超集,並進一步篩選內的對象應用:

_DbContext.Nodes 
    // filter nodes with any of the input tags 
    .Where(n => n.Tags.Any(t => tags.Contains(t.DisplayName))) 

    // select the information required 
    .Select(n => new { 
     n.NodeNativeId, 
     n.NodeName, 
     ClassName = n.NodeClass.ClassName, 
     TagNames = n.Tags.Select(t => t.DisplayName) }) 

    // materialize super set with database 
    .ToList() 

    // filter so that only nodes with all tags remain 
    .Where(n => !tags.Except(n.TagNames).Any()) 

    // produce result in anonymous class 
    .Select(n => new { n.NodeNativeId, n.NodeName, n.ClassName }) 
    .ToList(); 

編輯2

我只看到了一個又一個here可能爲你工作,但它要求Tag.DisplayName獨特,因爲如果你有相同的DisplayName多個標籤也可能失敗:

_dbContext.Nodes 
    .Where(n => n.Tags.Count(t => tags.Contains(t.DisplayName)) == tags.Count) 
    .Select(... 
+0

您是否檢查了使用'Except'生成的查詢?除了本地列表之外,會產生可怕的查詢,這些查詢很快就會超出最大嵌套級別。我學會了遠離它。 –

+0

@GertArnold:啊我不知道。在這種情況下,下拉超集並使用linq-to-objects進一步過濾會更好。 – jjj

+0

我想實現已編輯的答案,但是,它似乎存在一些語法錯誤。線路3上的選擇無效。 – blgrnboy