2010-12-08 68 views
3

我会采取C#和VB.NET的建议。LINQ to SQL查询父级和计数子级别

我正在使用LINQ来查询数据。我试图查询父项并计数子标签。

这里是我的标签表列:

TagId (int primary) 
TagName 
ParentId (int Allow NULL referred to TagId column) 

下面是一些样本数据:

TagId, TagName, ParentId 

1, Web Design, NULL 
2, HTML, 1 
3, Programming, NULL 
4, CSS 3, 1 

问题1:在我的查询结果,我想查询所有父标签用的总和儿童标签。像下面这样:

Web Design (2 sub tags) 
Programming (0 sub tags) 

问题2:如果孩子标签也有其自己的子标签

下面是一些样本数据:

TagId, TagName, ParentId 

1, Web Design, NULL 
2, HTML, 1 
3, Programming, NULL 
4, CSS 3, 1 
5, HTML 4, 2 
6, HTML 5, 2 

所需的查询结果:

Web Design (4 sub tags) 
Programming (0 sub tags) 

问题2是可选的bu如果你也提出一些建议,这将是非常好的。谢谢。

+0

您是否找到解决该问题的方法?你试过我的解决方案吗? – 2010-12-13 15:19:23

+0

还没有,我仍然环顾四周。有一篇关于LINQ AsHierarchy()扩展方法的文章,由Stefan Cruysberghs @ http://www.scip.be/index.php?Page=ArticlesNET23无论如何,我也会尝试你的建议。任何VB.NET版本的建议?无论如何,我会尝试将其转换为VB.NET – Narazana 2010-12-15 01:47:38

+0

我更新了我的答案,提供了非常好的解决方案。 – abatishchev 2011-01-21 08:41:50

回答

0

定义:

class Tag 
{ 
    public int Id { get; set; } 
    public string TagName { get; set; } 

    public int? ParentId { get; set; }  

    public IEnumerable<Tag> Children { get; set; } 
} 

数据:

int id = 0; 
var tags = new[] 
{ 
    new Tag 
    { 
     Id = ++id, 
     TagName = "Parent", 
     ChildNodes = new[] 
     { 
      new Tag { TagName = "Child1", Id = ++id, ParentId = 1 }, 
      new Tag { TagName = "Child2", Id = ++id, ParentId = 1 } 
     } 
    } 
    new Tag 
    { 
     Id = ++id, 
     TagName = "NoChildren" 
    } 
}; 

1, Parent, null 
2, Child1, 1 
3, Child2, 1 
4, NoChildren, null 

代码:

var q = from tag in tags 
     where tag.ParentId == null 
     select new 
     { 
      Name = tag.TagName, 
      ChildrenCount = tag.Children.Count() 
     }; 

foreach (var entry in q) 
{ 
    Console.WriteLine("{0} ({1} sub tags)", entry.Name, entry.ChildrenCount); 
} 

输出:

Parent (2 sub tags) 
NoChildren (0 sub tags) 

在复杂的层次结构的情况下,让所有的子节点递归地使用可以使用未来的扩展方法:

public static IEnumerable<Tag> GetChildTags(this Tag tag) 
{ 
    var children = tag.Children ?? Enumerable.Empty<Tag>(); 
    return children.SelectMany(c => GetChildTags(c)).Concat(children); 
} 
0

好的,最简单的方法是创建一个简单的结构,如果他们有父母,则连接标签,然后迭代儿童中心以产生每个标签的计数。

class Tag 
{ 
    public Tag(int id, int? parentId, string tag) 
    { 
     Id = id; 
     ParentId = parentId; 
     TagName = tag; 
    } 

    public int Id { get; set; } 
    public int? ParentId { get; set; } 
    public string TagName { get; set; } 
} 

class TagNode 
{ 
    public Tag Node { get; set; } 
    public IList<TagNode> ChildNodes { get; set; } 
    public int ChildNodeCount() 
    { 
     int count = 0; 
     if (ChildNodes != null) 
     { 
      foreach (var node in ChildNodes) 
      { 
       count += node.ChildNodeCount(); 
      } 
      count += ChildNodes.Count; 
     } 
     return count; 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var tags = new List<Tag>(); 
     tags.Add(new Tag(1, null, "Web design")); 
     tags.Add(new Tag(2, null, "Programming")); 
     tags.Add(new Tag(3, 1, "HTML")); 
     tags.Add(new Tag(4, 1, "CSS 3")); 
     tags.Add(new Tag(5, 3, "HTML 4")); 
     tags.Add(new Tag(6, 3, "HTML 5")); 

     IList<TagNode> nodes = tags.Select(y => new TagNode { Node = y, ChildNodes = new List<TagNode>() }).ToList(); 
     foreach (var node in nodes) 
     { 
      if (node.Node.ParentId.HasValue) 
       ConnectNodeToParent(nodes, node); 
     } 

     // print all nodes 
     Console.WriteLine("=== ALL NODES ==="); 
     nodes.ToList().ForEach(PrintNode); 

     // print root nodes 
     Console.WriteLine(Environment.NewLine + "=== ROOT NODES ==="); 
     nodes.Where(y => y.Node.ParentId.HasValue == false).ToList().ForEach(PrintNode); 

     Console.ReadLine(); 
    } 

    private static void PrintNode(TagNode node) 
    { 
     Console.WriteLine("Tag id: {0}, Tag name: {1}, Tag count: {2}", node.Node.Id, node.Node.TagName, node.ChildNodeCount()); 
    } 

    private static void ConnectNodeToParent(IList<TagNode> nodes, TagNode node) 
    { 
     var parentNode = nodes.Where(y => y.Node.Id == node.Node.ParentId.Value).Single(); 
     parentNode.ChildNodes.Add(node); 
    } 
} 

通过上面的代码,您可以获得每个标记的信息,而不仅仅是“父”标记。

1
public static IEnumerable<T> SelectDescendents<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> selector) 
{ 
    foreach(var item in source) 
    { 
    yield return item; 
    foreach(T item2 in SelectDescendents(selector(item), selector)) 
    yield return item2; 
    } 
} 

编辑: 用法:

Tags.where(t => t.tagID == 1).SelectDescendents(d => 
    Tags.where(t.parentID == d.TagId)).Count();