Doctrine class table 继承中的 `type` 列起什么作用?

What is the role played by the `type` column in Doctrine class table inheritance?

使用 Symfony 4/Doctrine 2.6。我有两个实体 Post 和 Comment。我希望两者都可以标记。所以我创建了一个实体标签。我使用 Doctrine 的 class table inheritance 来创建关系:

/**
 * @ORM\Entity(repositoryClass="App\Repository\TagRepository")
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="type", type="string")
 * @ORM\DiscriminatorMap({"post" = "PostTag", "comment" = "CommentTag"})
 */
abstract class Tag
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $title;

    // Getters and setters...
}

/** @ORM\Entity */
class PostTag extends Tag
{
    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Post", inversedBy="tags")
     */
    private $post;

    public function getPost(): ?Post
    {
        return $this->post;
    }
}

/** @ORM\Entity */
class CommentTag extends Tag
{
    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Comment", inversedBy="comments")
     */
    private $comment;

    public function getComment(): ?Comment
    {
        return $this->comment;
    }
}

这将创建 3 个 table:tagpost_tagcomment_tagpost_tag table 结构如下所示:

id | post_id

tag table 结构如下所示:

id | title | type

例如posts和标签相关联?如果我想将 post 13 与标签 test 相关联,结果会是这样吗:

post_tag table:

id | post_id
------------
1  | 13

tag table:

id | title | type
-----------------
1  | test  | post

如果是这样,那么如果我想将相同的标签 (test) 与评论相关联怎么办? tag table 会像这样吗?

id | title | type
--------------------
1  | test  | post
2  | test  | comment

这似乎有点多余。然后,相同的实体(test 标签)在 tag table 中由 2 行表示。我理解错了吗?

tl;dr:继承是错误的工具。标签是标签是标签。继承是 固有地 通过使用多个关联(多对多)提供的。

你的继承本质上说:有两种截然不同的标签类型,它们在本质上是不同的。一个标签,可以应用到帖子,一个标签,可以应用到评论,它们不是同一个标签,而是不同的标签。

由于两种标签存储在同一个table中,因此必须有一些机制来区分它们。这就是类型列的用途。 (所以,这基本上就是你主要问题的答案,afaict)

所以基本上,如果你想标记评论和博客(帖子)一样,这些是更常见的选项:

  1. 标签:(tag_id,tag_name,随便),Comment_tags:(tag_id,comment_id),Blog_tags:( tag_id, blog_id) ... (我想,这就是你 want/need)
  2. 标签:相同,标签分配:(tag_id, object_type, object_id) ... (不方便在 Doctrine 中,总体不利¹)

您选择了不同的方法:标签:(tag_id, tag_name, object_type),标签分配:(tag_id, object_id) (< -- 对象类型由 tagid 隐式给出,但由于您使用的是关系,Tagassignments 被分成 blog_tags 和 comment_tags)

但是,正如 Magnus Eriksson 正确评论的那样,这可能是有道理的。我有我的疑问。我认为,选项 1 或选项 2 都更为常见和方便。而且你应该放弃标签上的继承,而是在关联上添加继承(如果需要,你需要让它成为一个额外的实体才能使其工作),而是建议选择选项 1,因为它更容易实现学说及其注释。 (尽管您需要为应该可标记的每种不同对象类型添加一个 get{Object}s()。)

¹正如 Magnus 在下面正确评论的那样(以及我的共同评论):你失去了数据库提供的大部分优势,主要是性能、清晰度和一致性。我通常会反对这种方法。

为了后代,这是我实现@Jakumi 回答的方法:

  1. 废弃现有表格。
  2. 使用 symfony 控制台创建一个 Tag 实体,包含以下字段:

    a) post(类型:关系;多对多)

    b) comment(类型:关系;多对多)

    c) title(类型:字符串)

  3. 进行并运行 迁移。

这会自动创建表 tag_posttag_comment