在实体框架中创建嵌套实体的层次结构

时间:2014-01-23 07:39:50

标签: c# entity-framework

我正在尝试在Entity Framework中创建一个分层表示,在搜索之后我似乎找不到很多关于这个主题的内容。

前提:我正在开发一个反向链接监控工具,我可以在其中粘贴一堆URL以查看它们是否指向特定域。如果是这样,我想从列表中删除它们并将它们存储为顶级(第1层)反向链接。找到并删除直接链接到URL的所有反向链接后,我想运行列表中剩余的反向链接,看看它们是否指向新创建的顶级反向链接列表中的任何URL,以及指向顶级反向链接的那些,将它们存储为第2层反向链接。然后搜索第3层反向链接,依此类推,直到检查完整个列表。

我有一个网站实体,其中包含用于首次运行导入反向链接列表的网址。找到的那些被移动到列表中,并且在第二次循环时使用它们的URL,依此类推。

我最初在网站实体中为链接的每个“层”创建了一个单独的属性,但这似乎不是非常有效,因为在尝试渲染层次结构时,代码必须循环遍历每个层并重新匹配下面各层的网址,以重新创建实际的链接结构。

结束目标样本:

link hierarchy

所以我相信我应该创建一个单独的“反向链接”模型,并让每个反向链接实体存储它下面的反向链接列表,然后在尝试查看反向链接层次结构时,只需执行一个简单的循环,然后循环每个子反向实体。

反向链接实体的示例如下:

public class Backlink
{
    public int BacklinkID { get; set; }
    public string Url { get; set; }
    public string AnchorText { get; set; }
    public string LinksTo { get; set; }

    public int PageAuthority { get; set; }
    public int PageRank { get; set; }

    public virtual ICollection<Backlink> Backlinks { get; set; }
}

我编写了实际经过的代码并检查每个反向链接的HTML,以查找反向链接是否指向每个特定的URL,所以现在我正在尝试找出存储结果的最佳方法。

创建一个存储同一类型实体列表的实体是一种智能方法,还是我认为这一切都错了?以这种方式做某事会在查询数据库时损害性能吗?

理想情况下,我想使用延迟加载并且首先只显示顶层反向链接,然后在点击特定反向链接时,让EF再次调用以获取子反向链接等等 - 所以会这种具有延迟加载的存储方法是聪明的,还是应该废弃这个想法并为此找出一个完全不同的模式?

我对EF不太满意,所以对最佳方法的任何见解都会非常感激。

1 个答案:

答案 0 :(得分:3)

您尝试实施的内容称为邻接列表。似乎只需添加ICollection<Backlink>; Backlinks集合即可(当然,需要正确的模型配置)。然而,邻接列表本身并不是性能的好朋友,特别是它在EF中的典型实现(完全像你建议的那样)。有两种选择:

  1. 与您建议的一样,按需逐级加载链接。在这种情况下,选定的模型本身实际上工作正常(每个级别都非常简单SELECT,如提到的@Danexxtone)。但是,您会收到很多app server / DB的请求。因此,可能没有那么好的用户体验。
  2. 您可能希望加载整个树,以便毫不拖延地向用户显示节点。使用EF执行此操作意味着对导航集合进行递归,这实际上是最糟糕的想法 - 对DB的请求太多 似乎EF没有更多的选择。但是,您可以使用纯SQL(顺便说一下,通过EF数据上下文)......还有更多有趣的方法:
    1. CTE(就像@Jon提到的那样)。它适用于邻接列表,无需对DB结构进行任何其他更改。不错的选择,但不是最好的选择。
    2. 树路径列。让层次结构的根数为“1”,级别1链接为“2”,“3”,“4”,级别3链接为“5”。树中的每个节点(每个链接)可以具有唯一的字符串路径,如“1/2/5 /”。只需在DB中添加一个“Path”列 - 您就可以使用简单的LIKE表达式(甚至EF中的.StartsWith)提取子树
    3. 我假设你正在使用MS SqlServer DB。然后你有更好的选择 - hierarchyid数据类型。 EF不支持它,但是它提供了所有“树路径”功能 我写道,CTE不是最好的选择。这是因为性能 - 使用字符串树路径的查询效率更高(不要忘记索引)。 hierarchyid的性能比树路径好一点,但它的优势 - 用于树操作的内置API 另一个有趣的方法是Nested Sets。但是,我不推荐它 - 插入新节点的开销太大而且编码也不是那么容易。
  3. 结论

    如果您熟悉SQL本身并在EF中使用纯SQL,那么最好的选择可能是hierarchyid 如果您只想使用EF进行编码 - 邻接列表是唯一的选择。只是不要使用导航集合的递归遍历来检索深度子树 - 它可能真的很痛。