使用Linq

时间:2017-08-24 21:29:51

标签: c# linq linq-to-sql entity-framework-core

我有一个从存储过程构建的菜单,它返回一个文件夹层次结构。该过程返回FolderID,Name和ParentID。在我的Menu存储库中,我在我的文件夹列表中使用ForEach()来添加与父文件夹关联的每个SubFolder。

看起来像这样:

folders = await _dbcontext.MenuFolders.FromSql("EXEC UserMenuFolders @p0", UserID)
    .Select(x => new MenuFolder 
        {
            FolderID = x.FolderID, 
            FolderName = x.FolderName, 
            SortOrder = x.SortOrder, 
            SubofID = x.SubofID 
        })      
    .ToListAsync();

folders.ForEach(x => x.SubFolders = folders
    .Where(y => y.SubofID == x.FolderID)
    .OrderBy(y => y.SortOrder)
    .ToList());

这给了我一个看起来有点像的对象:

 "Folder 1": {
    "Sub Folder 1": [
        "SubFolder 1.1",
        "SubFolder 1.2"
    ],
    "Sub Folder 2": [
        "SubFolder 2.1",
        "SubFolder 2.2"
    ]
}, 
"Folder 2": {
    //Other sub Folders
 },
"SubFolder 1":{},
"SubFolder 1.1":{},
"SubFolder 1.2": {}

您可以看到SubFolders在那里两次,因为初始查询得到所有文件夹。如何从列表中删除子文件夹的文件夹?此外,我有兴趣了解是否有更有效的方法来创建此菜单结构,但请记住,我必须使用存储过程,因为授权逻辑已经在那里构建。

这是我无所作为的微弱尝试:

folders.RemoveAll(x => x.SubFolders.Any(c=> c.FolderID == x.FolderID));

以下是我的MenuFolders实体:

public int FolderID { get; set; }
public string FolderName { get; set; }        
public int ParentID { get; set; }
[ForeignKey("ParentID")]
public List<MenuFolder> SubFolders { get; set; }
public Int16 SortOrder { get; set; }

2 个答案:

答案 0 :(得分:2)

你接近你的尝试。基本上,您要删除的是子文件夹。这意味着如果文件夹的父ID作为任何文件夹的id存在,则它必须是子项,因此您可以安全地删除它。

folders.RemoveAll(x => folders.Any(f => f.FolderID == x.ParentID));

答案 1 :(得分:1)

只需使用递归。假设根文件夹(没有父文件夹的文件夹)有ParentId == 0,您可以使用以下内容:

public static List<MenuFolder> ToTree(IEnumerable<MenuFolder> flatList, int parentId = 0)
{
    var tree = flatList
        .Where(m => m.ParentID == parentId)
        .ToList();

    tree.ForEach(t => t.SubFolders = ToTree(flatList, t.FolderID));

    return tree;
}

然后回来:

var foldersTree = ToTree(folders);

注意:这将创建任意深度的树状结构(不仅仅是两个级别,如示例所示)