在Doctrine类表继承中`type`列扮演的角色是什么?

问题描述 投票:0回答:2

使用Symfony 4 / Doctrine 2.6。我有两个实体发布和评论。我希望两者都可以标记。所以我创建了一个实体Tag。我使用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个表:tagpost_tagcomment_tagpost_tag表结构如下所示:

id | post_id

tag表结构如下所示:

id | title | type

怎么样,例如帖子和标签相关联?如果我想将13test标签联系起来,结果如下:

post_tag表:

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

tag表:

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

?

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

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

这看起来有点多余。然后在test表中用2行表示相同的实体(tag标签)。我弄错了吗?

php symfony doctrine-orm polymorphic-associations
2个回答
2
投票

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

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

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

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

  1. 标签:(tag_id,tag_name,等等),Comment_tags:(tag_id,comment_id),Blog_tags:(tag_id,blog_id)...(我假设,这是你想要/需要的)
  2. 标签:相同,Tagassignments:(tag_id,object_type,object_id)...(在Doctrine中不方便,总体上不利¹)

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

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

¹asMagnus正确评论如下(并由我共同评论):你失去了数据库提供的大多数优势,主要是性能,清晰度和一致性。我一般会建议反对这种做法。


0
投票

为了后人,这是我实施@Jakumi答案的方法:

  1. 废弃现有表格。
  2. 使用symfony控制台创建一个Tag实体,其中包含以下字段: a)post(类型:关系;多对多) b)comment(类型:关系;多对多) c)title(类型:字符串)
  3. 制作并运行迁移。

这会自动创建表tag_posttag_comment

© www.soinside.com 2019 - 2024. All rights reserved.