RavenDB和层级文档

6

我在使用RavenDB解决这个问题时遇到了困难。我有这些类。为了保持示例简单,我从它们中排除了许多属性。

public class Menu
{
    public string Name { get; set; }
    public List<NavigationNode> Nodes { get; set; }
}

public class NavigationNode
{
    public string Text { get; set; }
    public Guid? PageId { get; set; }
    public string NodeType { get; set; }
    public List<NavigationNode> Nodes { get; set; }
}

public class Page
{
    public Guid PageId { get; set; }
    public string Slug { get; set; }
}

所以你可以看到这是关于呈现导航菜单的内容。节点列表是分层的,理论上可以无限深入(当然实际上只有2-4个子级)。起初我将Slug存储在Node中,但意识到,如果页面Slug更改,更改所有节点时,我必须遍历所有菜单,沿着层次结构向下爬并找到所有那些Slug值来更改它们,这听起来不像是最佳解决方案。
所以我想应该可以构建一个索引,将页面Slug与Node中的其余数据结合在分层结构中。
我一直在阅读Map Reduce、Multimap和递归的相关内容,但我甚至不知道从哪里开始。
我发现了这个http://ravendb.net/docs/2.0/client-api/querying/static-indexes/indexing-hierarchies 这里是我尝试的一个简单示例,只是为了开始做些什么,但我甚至无法让它工作,因为我真的不理解我上面链接的页面上的示例。
  public class NavigationIndex : AbstractIndexCreationTask<Menu>
   {
        public NavigationIndex()
        {
            Map = menus => from menu in menus
                           from node in Recurse(menu, x => x.Nodes)
                           select new
                                      {
                                          WhatIsThis = node // <- Why is this a collection?
                                      };
        }
    }

根据示例,节点不应该是一个集合,而是一个实际的NavigationNode对象。
在RavenDB中是否可能实现我想要的,并且我在示例中做错了什么?
如果您发现任何困惑,请随时提问。
对于造成的混乱,我表示歉意。我会尽力解释清楚。
编辑:
将PageId更改为字符串不会有问题。我使用Guids是因为我需要能够在插入之前生成主键ID。无论如何,我想从索引中查询包含页面Slug的导航链接的分层树形结构。这样我就可以在网站上递归循环出导航菜单。
回答Matt Johnson的问题:
1.我想要一个类的输出,您可以在下面看到
2.Page是一个单独的文档
3.我只会按Menu Name查询 public class NavigationIndexItem{ public string MenuName { get; set; } public string Text { get; set; } public string Slug { get; set; } public string NodeType { get; set; } public List ChildItems { get; set; } }
现在当我看到上面的类时,我觉得我可能走错了一点。
但无论如何,我会进行一些小的更改,并感谢马特的回答。然而,我仍然遇到了之前的同样问题。
你示例中的这一行:where node.PageId != null
node不是特定NavigationNode的实例,而是另一个集合,所以我无法检查它的PageId属性。我只能获得LINQ扩展列表。

问题:1)你想让输出看起来怎样?从你的问题中并不清楚。2)Page是一个单独的文档吗?如果是,您是否坚持使用Guid标识符?虽然可以实现,但Raven更适用于字符串标识符。3)您想通过什么查询? - Matt Johnson-Pint
2个回答

3
我假设你需要的是以下内容。请查看我的对原问题的评论,但我认为这就是你要的。
首先,你需要将Page类的id更改为Id,而不是PageId。这样可以使Raven使用你的guid作为文档id的一部分。虽然最好使用字符串Ids,但这仍将起作用。
然后你可以执行以下操作:
public class NavigationIndex : AbstractIndexCreationTask<Menu>
{
    public NavigationIndex()
    {
        Map = menus => from menu in menus
                       from node in Recurse(menu, x => x.Nodes)
                       where node.PageId != null
                       let page = LoadDocument<Page>("pages/" + node.PageId)
                       select new
                       {
                           menu.Name,
                           node.Text,
                           node.PageId,
                           page.Slug
                       };
    }
}

这里使用了 RavenDB 2.0 中新的 LoadDocument 特性,相较于多重映射来说更加适合你所要的场景。


我添加了一些澄清。这个类很混乱,因为StackOverflow的所见即所得编辑器无法将其格式化为代码:/尝试了几次。 - Kimpo
1
谢谢Matt,我解决了问题,并且得到了预期的结果。有一件有趣的事情是,我注意到我引用了RavenClient 1.x。在这种情况下,您不会得到实际的实例,而是一个集合。谈到这一行:where node.PageId!= null。在RavenClient 1.x中,node是一个集合,在2.x中我得到了实际的项。感谢您的帮助,非常感激! - Kimpo

0

将其更改为:

                            from node in Recurse(menu, x => x.Nodes.AsEnumerable())

但是节点仍然是一个集合。所以结果是相同的。我认为RavenDB页面上的教程可能有错别字。它展示了一个带有帖子和分层评论的例子。我有菜单和分层导航节点。 - Kimpo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接