【问题标题】:Using LINQ with tree structures将 LINQ 与树结构一起使用
【发布时间】:2013-08-20 16:44:22
【问题描述】:

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

这里真正的问题是可能有很多设备,所以我想要分页,所以理想情况下这一切都可以使用 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)
    }
}

【问题讨论】:

  • 使用数据库上的公用表表达式准备视图并将其映射到 EF。
  • 不确定你会怎么做?
  • 何去何从?您可以像表格一样轻松地将 View 映射到 EF,但您必须记住,使用该映射可能无法插入/更新。
  • 我不确定的是那个位(视图,映射它,它意味着什么?):)
  • 我会为此使用递归函数 - 主要是因为它(在我看来)使代码更具可读性。据我所知,您可以这样做:stackoverflow.com/questions/11830174/…

标签: c# linq entity-framework lambda


【解决方案1】:

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

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

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

这基本上是从here偷来的(只是稍作修改)

我相信你可以这样做:

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

【讨论】:

  • 这里唯一的问题是调试,当你有堆栈溢出以外的异常时。您没有调用堆栈和每个深度的局部变量状态。对于更简单的逻辑,它是可读的,你只是在迭代,但是当你有更多的条件要评估时,它就变得困难了。您如何知道当前迭代的深度?尝试打印缩进等于深度的树,看看代码有多脏。
  • 我认为另一个问题是我完全没有回答手头的问题(我写了上面的答案)。此解决方案仍将在 C# 类中进行排序和分页。似乎我渴望写答案而不是阅读和理解问题 - 抱歉。
  • @Ykok 太好了,你把我的功劳归功于我,这是一些适当的礼仪
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多