LINQ to SQL для запроса родителя и подсчета дочерних элементов в иерархии - PullRequest
3 голосов
/ 08 декабря 2010

Я бы принял предложение C # и VB.NET.

Я использую 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 не является обязательным, но будет очень хорошо, если вы также дадите несколько советов. Спасибо.

Ответы [ 3 ]

1 голос
/ 20 января 2011
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;
  }
 }

Edit: Использование:

Tags.where(t => t.tagID == 1).SelectDescendents(d => 
  Tags.where(t.parentID == d.TagId)).Count();
0 голосов
/ 20 января 2011

Определение:

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 голосов
/ 09 декабря 2010

Хорошо, самый простой способ - создать простую структуру, в которой вы соединяете свои теги, если у них есть родители, а затем перебираете дочерние элементы, чтобы получить счетчик для каждого тега.

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

С помощью приведенного выше кода вы получаете информацию для каждого тега, а не только для «родительских» тегов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...