2015-06-19 133 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