使用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个表:tag
,post_tag
和comment_tag
。 post_tag
表结构如下所示:
id | post_id
tag
表结构如下所示:
id | title | type
怎么样,例如帖子和标签相关联?如果我想将13
与test
标签联系起来,结果如下:
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
标签)。我弄错了吗?
tl; dr:继承是错误的工具。标签是标签是标签。通过使用多个关联(多对多)来固有地提供继承。
你的继承本质上说:有两种不同类型的标签,它们本质上是不同的。一个标签可以应用于帖子,一个标签可以应用于评论,这些标签不是相同的标签,而是不同的标签。
由于两种标签都存储在同一个表中,因此必须有一些关于如何区分这些标签的机制。这就是类型列的用途。 (所以,这基本上是你的主要问题的答案,afaict)
基本上,如果你想标记评论和博客(帖子),这些是更常见的选项:
您选择了不同的方法:标签:(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正确评论如下(并由我共同评论):你失去了数据库提供的大多数优势,主要是性能,清晰度和一致性。我一般会建议反对这种做法。
为了后人,这是我实施@Jakumi答案的方法:
Tag
实体,其中包含以下字段:
a)post
(类型:关系;多对多)
b)comment
(类型:关系;多对多)
c)title
(类型:字符串)这会自动创建表tag_post
和tag_comment
。