我有一个如下所示的数据库表:
MenuItemID | int [Primary Key] 1 -----+
MenuItemName | nvarchar(100) |
ParentID | int * -----+
正如您在上面的示意图中所看到的,ParentID列引用了MenuItemID,因此我们可以获得分层输出。
上表中的样本数据如下所示:
从上面的示例数据中,我希望输出如下:
Electronics
Mobile
Desktop
Laptop
Lenovo
Dell
Sports
Cricket
Football
Hockey
Stationary
Books
Pens
Pencils
Erasers
我尝试了什么:
我已经尝试了下面提到的代码,我尝试使用GroupJoin扩展方法来实现所需的输出:
class Program
{
static void Main(string[] args)
{
OnlineShoppingEntities db = new OnlineShoppingEntities();
var x = db.MenuItems.GroupJoin(db.MenuItems,
m => m.MenuItemID,
m => m.ParentID,
(parentMenuItems, childMenuItems) => new
{
ParentMenuItems = parentMenuItems,
ChildMenuItems = childMenuItems
});
foreach (var v in x)
{
Console.WriteLine(v.ParentMenuItems.MenuItemName);
foreach (var m in v.ChildMenuItems)
{
Console.WriteLine("\t" + m.MenuItemName);
}
}
}
}
我得到的输出:
我对输出非常惊讶,因为我预期上面提到的所需输出。
答案 0 :(得分:2)
您的解决方案可以在SO:Hierarchical data in Linq - options and performance找到。
我不会抽象代码因为有那么多答案可以解决你的问题,我特别喜欢AsHierarchy()
linq扩展方法,如Kyle对该问题的回答所示。
var hierachy = dc.Employees.ToList().AsHierarchy(e => e.EmployeeID, e => e.ReportsTo);
code for the extension by Stefan Cruysberghs是:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ScipBe.Common.LinqExtensions
{
// Stefan Cruysberghs, http://www.scip.be, March 2008
/// <summary>
/// Hierarchy node class which contains a nested collection of hierarchy nodes
/// </summary>
/// <typeparam name="T">Entity</typeparam>
public class HierarchyNode<T> where T : class
{
public T Entity { get; set; }
public IEnumerable<HierarchyNode<T>> ChildNodes { get; set; }
public int Depth { get; set; }
}
public static class LinqExtensionMethods
{
private static System.Collections.Generic.IEnumerable<HierarchyNode<TEntity>> CreateHierarchy<TEntity, TProperty>
(IEnumerable<TEntity> allItems, TEntity parentItem,
Func<TEntity, TProperty> idProperty, Func<TEntity, TProperty> parentIdProperty, int depth) where TEntity : class
{
IEnumerable<TEntity> childs;
if (parentItem == null)
childs = allItems.Where(i => parentIdProperty(i).Equals(default(TProperty)));
else
childs = allItems.Where(i => parentIdProperty(i).Equals(idProperty(parentItem)));
if (childs.Count() > 0)
{
depth++;
foreach (var item in childs)
yield return new HierarchyNode<TEntity>() { Entity = item, ChildNodes = CreateHierarchy<TEntity, TProperty>
(allItems, item, idProperty, parentIdProperty, depth), Depth = depth };
}
}
/// <summary>
/// LINQ IEnumerable AsHierachy() extension method
/// </summary>
/// <typeparam name="TEntity">Entity class</typeparam>
/// <typeparam name="TProperty">Property of entity class</typeparam>
/// <param name="allItems">Flat collection of entities</param>
/// <param name="idProperty">Reference to Id/Key of entity</param>
/// <param name="parentIdProperty">Reference to parent Id/Key</param>
/// <returns>Hierarchical structure of entities</returns>
public static System.Collections.Generic.IEnumerable<HierarchyNode<TEntity>> AsHierarchy<TEntity, TProperty>
(this IEnumerable<TEntity> allItems, Func<TEntity, TProperty> idProperty, Func<TEntity, TProperty> parentIdProperty)
where TEntity : class
{
return CreateHierarchy(allItems, default(TEntity), idProperty, parentIdProperty, 0);
}
}
}
答案 1 :(得分:0)
当然,如果您的数据只有3个级别,那么为简单起见,您可以使用其他GroupJoin()
执行此操作:
var hierarchical = menuItems.Where(m => m.ParentID == null)
.GroupJoin(menuItems,
m => m.MenuItemID,
m => m.ParentID,
(parentMenuItems, childMenuItems) => new
{
ParentMenuItems = parentMenuItems,
ChildMenuItems = childMenuItems.GroupJoin(menuItems,
m => m.MenuItemID,
m => m.ParentID,
(subParentMenuItems, subChildMenuItems) => new
{
ParentMenuItems = subParentMenuItems,
ChildMenuItems = subChildMenuItems
})
});
foreach(var menu in hierarchical)
{
Console.WriteLine(menu.ParentMenuItems.MenuItemName);
foreach(var submenu in menu.ChildMenuItems)
{
Console.WriteLine("\t" + submenu.ParentMenuItems.MenuItemName);
foreach(var subitem in submenu.ChildMenuItems)
{
Console.WriteLine("\t\t" + subitem.MenuItemName);
}
}
}