【问题标题】:How do i manage M:N Post-Tag relationship (eg. Edit/Delete)我如何管理 M:N Post-Tag 关系(例如编辑/删除)
【发布时间】:2010-07-29 13:16:10
【问题描述】:

当我开始尝试实现这一点时,我陷入了困境。

一些业务规则

1 个帖子可以有多个标签。 1个标签可以有很多帖子

数据库看起来像。

  • 帖子(ID、标题、正文...)
  • Posts_Tags(帖子、标签)
  • 标签(id、tag、...)

当我插入 - 直截了当

  • 标签将来自用户输入的逗号分隔值
  • explode($tags) 获取单个标签
  • foreach $标签
    • 检查标签是否存在
    • 如果是,获取 id
    • 如果没有,插入标签并获取 id
  • 插入带有标签的帖子

我想知道这是否是最好的方法?如果标签存在,我可以取消循环到 chk 吗?或将其简化为 1 个查询?

更新帖子,有点难

  • 我如何检查用户是否更新了任何标签。另一个循环?但这次会有一些变化(斜体)

  • explode($tags) 获取单个标签

  • foreach $标签
    • 检查这篇文章是否被标记了这个标签
    • 如果没有,
      • 标签是否存在?
        • 是的,获取 ID
        • 不,插入并获取 id
    • 如果是,获取 id
  • 用标签更新帖子

嗯,...更新比较混乱,你将如何实现?

我正在使用 PHP 5.3、Zend Framework 1.10、Doctrine 2

【问题讨论】:

    标签: php sql doctrine


    【解决方案1】:

    我认为post-tags的关系应该是多对多的;即:帖子有并且属于许多标签。这可以通过联结表来实现。这里有一些关于这个主题的literature。那么……

    插入:做你现在正在做的同样的事情,除了你可以在一个查询中获取所有标签:

    SELECT name FROM tags WHERE name IN ($tags)
    

    更新:简单的出路:删除所有当前标签,插入标签,就好像它们都是新的一样。或者……

    $tags = explode(',' $_POST['tags']); // remove whitespaces
    
    # delete all current tags that were not included in the edit
    DELETE FROM post_tags WHERE post_id=$post_id AND tag_id NOT IN ($tags)
    
    # find out what the current tags are, use a JOIN to find out their labels
    SELECT tag_id FROM post_tags WHERE post_id=$post_id
    fetch results, remove found tags from $tags, then
    foreach new $tag, insert as if they were new
    

    【讨论】:

    • 你是对的,更新了我的帖子。我猜删除和插入所有标签不会降低性能太多?
    • 我从不喜欢多对多的标记模式。必须将 3 个表而不是 2 个表连接在一起来获取标签列表似乎效率低下,特别是因为 tag 和 post_tag 表可能会变得相当大,具体取决于站点的活跃程度。
    • @KallDrexx 不幸的是似乎是 best way 这样做
    • @KallDrexx,是的,但我想我也会限制 1 个帖子,最多可以说 5 个标签,就像这里一样?
    • @NullUserException - 为什么它比使用一对多更好?我知道它在空间方面更有效且更规范化,但在性能方面,M2M 比 O2M 更好吗?
    【解决方案2】:

    我做的标签和你更新的伪代码非常相似,除了一个额外的步骤。您需要检查以确保不存在用户输入中不存在的帖子的标签。例如,如果一个帖子被标记为“php,sql,doctrine”并且用户将标签更改为“c#,sql,doctrine”,那么您也必须知道删除 php 标签。

    所以我的代码循环遍历现有标签以查看需要删除哪些标签,然后我遍历用户提供的标签以查看需要添加哪些标签。

    【讨论】:

      【解决方案3】:

      更新的想法:

      • 将用户 JS 启用/禁用的值存储在隐藏值中
      • 将 onchange 事件绑定到标签输入,然后将隐藏变量设置为 true,以便您知道标签已更改
      • 如果启用 JS 并且标签已更改,请删除属于此帖子的所有标签,然后插入实际标签(如第一个)
        • 回退:如果 JS 禁用,您需要检查提交的标签与保存的标签。

      【讨论】:

      • 假设用户启用了 js,这将是一种更有效的方法。
      • 你仍然需要在 PHP 端进行处理,因为你不能保证 JS 已启用。
      【解决方案4】:

      对于您的第一个问题,您可以将事情简化为一个查询。 (非参数化的)SQL 看起来像这样:

      SELECT * FROM Tags WHERE name='foo' OR name='bar' OR name='etc'
      /* and so on and so forth */
      

      然后您可以在 PHP 代码中循环检查返回了哪些标签;我会使用 key_exists("keyname", $associativeArrayContainingQueryResults)。

      我也会为您查询的第二部分做类似的事情。不过,我不知道性能优势是什么。 SQL 可能会更好地缓存几个较小查询的结果,但我不知道总体上它是否会更快。

      【讨论】:

      • 嗯,我想我会做一个IN()SELECT * FROM Tags WHERE name IN ('foo', 'bar', 'baz')
      • 这样会更容易生成。 :-)
      • 你为什么这么说?在我看来,而不是生成name = 'foo',我只生成'foo' ltr 使用', ' 作为胶水将它们内爆并将其附加到WHERE 子句?
      • 是的,我想这实际上并不容易。简短的代码让一切看起来都很简单。
      【解决方案5】:

      我认为 Doctrine 中有一个可标记的行为。看看这个,这会有所帮助。

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-21
      • 1970-01-01
      • 2019-08-30
      相关资源
      最近更新 更多