Using Symfony 4/Doctrine 2.6.我有两个实体发布和评论。我希望两者都是可标记的。所以我创建了一个实体标签。我使用 Doctrine 的类表继承来创建关系:
/**
* @ORMEntity(repositoryClass="AppRepositoryTagRepository")
* @ORMInheritanceType("JOINED")
* @ORMDiscriminatorColumn(name="type", type="string")
* @ORMDiscriminatorMap({"post" = "PostTag", "comment" = "CommentTag"})
*/
abstract class Tag
{
/**
* @ORMId()
* @ORMGeneratedValue()
* @ORMColumn(type="integer")
*/
private $id;
/**
* @ORMColumn(type="string", length=255)
*/
private $title;
// Getters and setters...
}
/** @ORMEntity */
class PostTag extends Tag
{
/**
* @ORMManyToOne(targetEntity="AppEntityPost", inversedBy="tags")
*/
private $post;
public function getPost(): ?Post
{
return $this->post;
}
}
/** @ORMEntity */
class CommentTag extends Tag
{
/**
* @ORMManyToOne(targetEntity="AppEntityComment", 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
标记)由tag
表中的 2 行表示。我弄错了吗?
tl;大卫:继承是错误的工具。标签就是标签就是标签。继承本质上是通过使用多个关联(多对多)提供的。
你的继承本质上是说:有两种不同类型的标签,本质上是不同的。一个标签可以应用于帖子,一个标签可以应用于评论,它们不是相同的标签,而是不同的标签。
由于这两种标签都存储在同一个表中,因此必须有一些机制来区分其中一种。这就是类型列的用途。(所以,这基本上是你主要问题的答案,afaict)
因此,从本质上讲,如果您想标记评论和博客(帖子),这些是更常见的选项:
标签: (tag_id, tag_name, 随便), Comment_tags: (tag_id,- comment_id), Blog_tags: (tag_id, blog_id) ...(我假设,这就是你想要/需要的)
- 标签:相同, 标签分配: (tag_id, object_type, object_id) ...(在教义上不方便,总体上不利¹)
您选择了不同的方法:标签:(tag_id、tag_name、object_type)、标签分配:(tag_id、object_id)(<-对象类型由tagid隐式给出,但由于您使用的是关系,标签分配分为blog_tags和comment_tags)
然而,正如马格努斯·埃里克森(Magnus Eriksson)正确评论的那样,这可能是有道理的。我有我的怀疑。我认为,选项 1 或选项 2 更常见和方便。您应该删除标签上的继承,而是在关联上添加继承(如果需要,您需要使其成为额外的实体以使其工作),而是建议选择选项 1,因为它更容易实现与原则和它的注释。(尽管您需要为每个应该可标记的不同对象类型添加一个 get{Object}s()。
¹正如Magnus在下面正确评论的那样(并由我共同评论):你失去了数据库提供的大部分优势,主要是性能,清晰度和一致性。我一般建议不要这样做。
为了后代,这是我实现@Jakumi答案的方法:
- 废弃现有表。
使用symfony控制台创建一个
Tag
实体,具有以下字段:a)
post
(类型:关系;多对多)b)
comment
(类型:关系;多对多)c)
title
(类型:字符串)- 进行和运行迁移。
这会自动创建表tag_post
和tag_comment
。