使用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个表: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
标记)。我搞错了吗?
答案 0 :(得分:2)
tl; dr:继承是错误的工具。标签是标签是标签。继承是通过使用多个关联(多对多)而固有地提供的。
您的继承从本质上说:标签有两种不同的类型,它们本质上是不同的。可以将一个标签应用于帖子,将一个标签应用于评论,这些标签不是相同的标签,而是不同的标签。
由于两种标记都存储在同一张表中,因此必须存在 some 机制来区分一种标记。这就是类型列的用途。 (因此,这实质上是您对主要问题afaict的回答)
因此,从本质上讲,如果您想同时标记评论和博客(帖子),则这些是更常见的选项:
您选择了另一种方法:标签:(tag_id,tag_name,object_type),Tagassignments:(tag_id,object_id)(<-对象类型由tagid隐式给出,但是由于使用关系,Tagassignments被拆分了进入blog_tags和comment_tags)
但是,正如Magnus Eriksson正确评论的那样,这可能是有道理的。我有疑问我认为,选项1或选项2更为常见和方便。并且您应该将继承放在Tag上,而在关联上添加继承(如果需要,您需要使其成为一个额外的Entity才能起作用),而是建议选择选项1,因为这样做很容易实现学说及其注释。 (尽管您需要为应该标记的每种不同对象类型添加一个get {Object} s()。)
¹如马格努斯(Magnus)在下面的正确评论(并由我共同评论):您失去了数据库提供的大多数优势,主要是性能,清晰度和一致性。我通常会建议不要使用这种方法。
答案 1 :(得分:0)
For the sake of posterity, this is the approach I took to implement @Jakumi's answer:
Create a Tag
entity with the symfony console, with the following fields:
a) post
(type: relation; many-to-many)
b) comment
(type: relation; many-to-many)
c) title
(type: string)
This automatically created the tables tag_post
and tag_comment
.