评论系统设计

时间:2011-04-15 14:22:46

标签: asp.net database-design foreign-keys relational-database normalization

以下是我目前的评论系统设计:

enter image description here

我正在为一个有很多领域,博客,教程,手册等的网站开发它。应该为每个(tblBlogCommentstblTutorialComments)等开发一个单独的评论表,我正试图采用一种适合所有方法的结构。

这样,我可以将评论系统转换为Web控件,只需将其放在我想要评论的任何页面上。这意味着我只有一套规则,一组代码文件需要维护。

唯一的问题是,提出了一个“好的”方法来确定属于哪个部分(博客/教程/手册)。

例如,一种解决方案是:

tblComment
-------------
Section (int)
SectionIdentifier (int)

Section”映射到网站每个部分的唯一位置,EG:

Blog = 1
Articles = 2
Tutorials = 3
...

SectionIdentifier是该页面的某种唯一ID,例如:

ViewBlog.aspx?ID=5

这将是第1部分,标识符5.现在,Section = 1SectionIdentifier = 5的评论意味着它是对博客条目号5的评论。

这很有效,但是以可维护性和可靠结构为代价,因为SectionIdentifier是匿名的,不能建立任何关系。

这个设计是否正常,或者是否有更好的解决方案(IE某种父表用于评论?)

5 个答案:

答案 0 :(得分:3)

在Codd最初为关系模型设计的内容中,外键可以引用不同表中的多个主键,如果任何一个表包含该值,则引用完整性有效。

不幸的是,SQL是对原始愿景的一种苍白反映,因为它没有像你所指出的那样提供这种能力。

一个标准的解决方法是创建一个新的关系,其中包含所有其他关键字。但在这种情况下,这不是一个非常好的解决方案,因为如果一次发生大量插入,它会产生争用点。

我处理这个的方法是创建一个值 - 让我们称之为Comment-Anchor - 你可以把它放到每个有评论的表中。此值(与设计良好的数据库中的所有其他键不同)应为GUID。然后每个注释都可以有一个Comment-Anchor,指示它引用的值。

通过将其设为GUID,您可以随时在博客或教程中插入唯一值,而无需争用。您不必在任何地方维护Comment-Anchors的主列表,也不必与任何其他部分争用或阻止。

这对于查找单个博客条目的所有评论的正常用例非常有用。换句话说,从评论到被评论的东西,你可以在评论表中放置一个标志来识别哪个表被引用,但我不会这样做。我会搜索所有表格,也许是查看或其他内容。反向查询是非常罕见的,我没有看到维护它的基础设施有多大意义,而标志将是冗余数据,这是RDBMS的祸根。

该系统的另一个好处是它易于扩展。如果您创建新类型的数据,或决定向现有数据类型添加注释,则只需将Comment-Anchor列添加到表中。不必在数据库方面进行额外的工作。甚至处理注释的中间件部分也不需要以任何方式进行修改,因为它不知道哪些内容需要注释。

答案 1 :(得分:2)

对于表格设计,我会尽可能地模拟它在这种情况下的类结构。从你所说的,这就是它的样子(粗略地):

Section <- Post <- Comment

所以,你有:

  1. 章节表(例如博客,文章,教程等)
  2. 邮政表(每个部分的个别帖子)
  3. 评论表(每篇帖子的评论)
  4. 每个帖子都会引用它的部分,每个评论都会引用它的帖子。数据库可以将引用作为漂亮,干净的外键,并且类可以在应用程序需要时在关系的一侧或两侧具有列表。

    对我来说,这看起来像一个漂亮,简单,灵活的结构,不会使事情变得复杂,仍然允许你挂掉额外的位,比如编辑和投票。

答案 2 :(得分:1)

我将避免创建一个id列,该列根据同一个表中的另一列定义不同的关系。例如,在您的示例中,SectionIdentifier可以表示任意数量的外键引用,具体取决于Section的值。这使我在一般原则上屈服了。它还保留了现代RDBMS平台的几个优点,因为它不受支持。

这些不同部分的总体架构是如何构建的?我已经使用了一些CMS,这些CMS需要您的每个部分共享一个公共基础实体,称之为“模块”或“插件”。然后,给定模块的每个实例都有自己的id,用于映射到该特定实例所需的任何内容。

如果这是一个可行的架构方向,您也可以使用ModuleInstanceID作为注释的外键。您只需要决定如何将给定类型的模块/插件注册为有效的评论目标。

无论如何,你能否透露一下如何将你的部分放在引擎盖下?

答案 3 :(得分:0)

好像。您的评论系统包含许多类型的评论(tblBlogComments,tblTutorialComments .....等)。我想建议你采用策略设计模式。

让我们说吧。你有一个IComment接口。并且所有类型的注释类都实现了IComment接口。

interface IComment
{
    int ID {get; set; }
    int Section  {get; set; }
    ....
}

class BlogComment : IComment
{
    ....
}

class TutorialComment : IComment
{
    ....
}

一个只知道如何处理IComment的WebControl

class WebControl
{
    IComment _comment = null;

    public WebControl(IComment comment)
    {
        _comment = comment;
    }
}

当然,您需要一个CommentCreater来加载来自数据库的注释数据并构建注释对象。

public static void main()
{
    var creater = new CommentCreater();
    IComment comment1 = creater.CreateBlogComment()
    WebControl webcontrol = new WebControl(comment1);
    ......

    IComment comment2 = creater.CreateTutorialComment()
    webcontrol = new WebControl(comment2);
    ........
}

这样,您的网络控件就可以以同样的方式处理所有类型的评论。无论究竟是什么样的评论。你也可以保持CommentCreater正确构建每种评论类。

答案 4 :(得分:0)

查看this question的已接受答案。阅读所有评论。