【问题标题】:Remove Parents that are children in the same Object using Linq使用 Linq 删除作为同一对象中子级的父级
【发布时间】:2017-08-24 21:29:50
【问题描述】:

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

看起来像这样:

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 存在两次,因为初始查询得到 All Folders。如何从列表中删除作为子文件夹的文件夹?另外,我很想看看是否有更有效的方法来创建这个菜单结构,但请记住,我必须使用存储过程,因为授权逻辑已经在那里构建。

这是我没有做任何事情的微弱尝试:

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

【问题讨论】:

  • 您想从样本中删除哪个SubFolder 1.1?第一个还是第二个? 请附上UserMenuFolders的源代码。
  • 第二个。如果文件夹在 ForEach 之后变成了子文件夹,我想删除它。

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


【解决方案1】:

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

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

【讨论】:

  • 这些层次结构有时会相当复杂,我在@Eric 之前做过类似的事情:)
【解决方案2】:

只需使用递归。假设根文件夹(没有父文件夹)有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);

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

【讨论】:

  • 不过,请记住,为了简单起见,我的示例只有 2 个级别,但我的解决方案还创建了一个与您的类似的任意深度的树。但是,在您的解决方案中,您不必像我对 RemoveAll 方法调用所做的那样减少任何脂肪。很好的答案,谢谢!
猜你喜欢
  • 2021-05-30
  • 2021-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多