EF LINQ - 返回包含整个集合的实体

本文关键字:集合 实体 包含整 LINQ 返回 EF | 更新日期: 2023-09-27 17:57:07

我正在尝试对以下 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);
}

查询返回与标记无关的单个节点。 我希望它做的是返回具有所有标签的任何节点。

EF LINQ - 返回包含整个集合的实体

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

按照目前的构造方式,您最终只会得到Node,其中Node.Tags中的每个标签在tags白名单中都有一个名称,其中包括没有标签的Node


您可能希望从此处对子集使用答案:

_DbContext.Nodes
    .Where(n => !tags.Except(n.Tags.Select(t => t.DisplayName)).Any()) 
    .Select(...
  • set1.Except(set2)包含不在set2中的set1元素
  • !set1.Except(set2).Any() == true set2是否包含set1的每个元素

编辑

评论中指出,使用 Except 可能会生成有问题的查询,所以我认为另一种选择是从数据库中获取超集,并进一步过滤应用程序中的对象:

_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

我刚刚在这里看到了另一个可能适合您的,但它要求Tag.DisplayName是唯一的,因为如果您有多个具有相同DisplayName的标签,它可能会失败:

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