将LINQ与树结构结合使用

本文关键字:结合 结构 LINQ | 更新日期: 2023-09-27 18:28:06

我使用EF和Linq从数据库返回值。我有一个Folder结构,文件夹可以包含Folder的列表或Device的列表。我想要的是能够构建一个位于文件夹内(或文件夹下)的所有Device的列表,包括属于该文件夹的任何文件夹(想象一下,我想查看顶层目录中的所有文件,该目录也包括子目录)。

这里真正的关键是可能有很多设备,所以我想要分页,所以理想情况下,这一切都可以用LINQ完成,这样我就可以在返回结果集之前对查询进行排序和分页。

这是我的设置的基本版本(为了简单起见,删除了密钥、注释和其他内容)

public class Folder
{
    public virtual ICollection<Folder> Children { get; set; }
    public virtual ICollection<Device> Devices { get; set; }
}
// This is the function I currently have that only returns 1 folder
// needs to somehow be expanded to return devices for all folders beneath it too
function GetFolderDevices(int folderId, PaginationOptions options)
{
    // Get all folders and devices
    using (var dbObj = this.context.CreateDBContext())
    {
        EMDB.Models.Folder folder = dbObj
            .AddressBook
            .Include(a => a.Devices.Select(d => d.Settings))
            .FirstOrDefault(f => f.FolderId == folderId);
        // apply pagination here (already taken care of)
    }
}

将LINQ与树结构结合使用

我相信您可以使用迭代器。像这样的东西可能会起作用:

    static IEnumerable<Folder> Descendants(Folder root)
    {
        var nodes = new Stack<Folder>(new[] { root });
        while (nodes.Any())
        {
            Folder node = nodes.Pop();
            yield return node;
            foreach (var n in node.Children) nodes.Push(n);
        }
    }

对于产生的每个节点,它将只遍历以前的子节点。

这基本上是被盗的(只是略有修改)从这里

我相信你可以这样做:

    // This is the function I currently have that only returns 1 folder
    // needs to somehow be expanded to return devices for all folders beneath it too
    function GetFolderDevices(int folderId, PaginationOptions options)
    {
            // Get all folders and devices
            using (var dbObj = this.context.CreateDBContext())
            {
                    EMDB.Models.Folder folder = dbObj
                            .AddressBook
                            .Include(a => a.Devices.Select(d => d.Settings))
                            .FirstOrDefault(f => f.FolderId == folderId);
                    var result = from fold in Descendants(folder)
                                 select fold;
                    // apply pagination here (already taken care of)
            }
    }