Database 从一个实体到不同表中多个实体的符号关系
我有一个带有注释实体的symfony应用程序,我想用关系属性将它链接到许多实体。但说到很多实体,我指的不是很多对象,而是很多类 在我的应用程序中,注释可以是关于不同事物的:绘图实体、文本实体、复合实体或照片实体。每个实体对应一种艺术作品,每一种都有不同的属性和不同的页面。每一个都可以评分和评论 问题是:当我想在我的注释实体中创建关系属性时,我只需要指出一个实体。我希望一些评论是关于一个图形实体,一些是关于文本等 我看到了一个解决方案:按实体创建一个实体注释作为链接,但我的应用程序将有很多实体,并且我的代码将被复制,这对将来的更改不太好,等等 有没有办法将一个实体与多种不同类型的实体联系起来 多谢各位 编辑4:下面所有以前的编辑都是毫无意义的 我这样做是为了让初学者能够看到我的一些代码,有一个详细的继承映射示例,当我第一次尝试时,我可以得到它,我并没有理解所有内容,但我只是意识到我犯了一个愚蠢的错误:Database 从一个实体到不同表中多个实体的符号关系,database,symfony,doctrine-orm,symfony4,relation,Database,Symfony,Doctrine Orm,Symfony4,Relation,我有一个带有注释实体的symfony应用程序,我想用关系属性将它链接到许多实体。但说到很多实体,我指的不是很多对象,而是很多类 在我的应用程序中,注释可以是关于不同事物的:绘图实体、文本实体、复合实体或照片实体。每个实体对应一种艺术作品,每一种都有不同的属性和不同的页面。每一个都可以评分和评论 问题是:当我想在我的注释实体中创建关系属性时,我只需要指出一个实体。我希望一些评论是关于一个图形实体,一些是关于文本等 我看到了一个解决方案:按实体创建一个实体注释作为链接,但我的应用程序将有很多实体,并
* @DiscriminatorMap({"comment" = "Comment", "comment" = "CommentDrawing", "commentphoto" = "CommentPhoto", "commenttexte" = "CommentTexte"})
我忘了commentcompo=commentcompo
我写了comment=comment和comment=CommentDrawing,这两个都是由comment引用的
这就是为什么我不得不把注释作为鉴别器,而不是注释
为那个愚蠢的错误感到抱歉,这么多代码行我都没注意到
对于那些第一次使用继承映射并需要信息的人,我现在尝试用表单填充注释。如果你想做同样的事情,你可能会来这里寻求答案,我认为这是解决方案:
编辑:
感谢下面Jakumi的回答,我使用了继承映射。我选择了第一种解决方案:单表解决方案。但是我试过了,我没有错误信息,但这对我来说不起作用,几个小时后我仍然不明白我做错了什么
我的注释类我的注释层次结构中最顶层的类,它有CommentDrawing、CommentCompo、CommentPhoto、CommentTexte作为子注释是抽象的,因为我有一个错误告诉我,这指示我将其抽象化以解决错误:
<?php
namespace App\Entity;
use App\Entity\Comment;
use App\Entity\CommentPhoto;
use App\Entity\CommentTexte;
use App\Entity\CommentDrawing;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\InheritanceType;
use Doctrine\ORM\Mapping\DiscriminatorMap;
use Doctrine\ORM\Mapping\DiscriminatorColumn;
/**
* @ORM\Entity(repositoryClass="App\Repository\CommentRepository")
* @InheritanceType("SINGLE_TABLE")
* @DiscriminatorColumn(name="discriminator", type="string")
* @DiscriminatorMap({"comment" = "Comment", "comment" = "CommentDrawing", "commentphoto" = "CommentPhoto", "commenttexte" = "CommentTexte"})
*/
abstract class Comment
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="datetime")
*/
private $createdAt;
/**
* @ORM\Column(type="text")
*/
private $content;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="comments")
* @ORM\JoinColumn(nullable=false)
*/
private $author;
public function getId(): ?int
{
return $this->id;
}
public function getCreatedAt(): ?\DateTimeInterface
{
return $this->createdAt;
}
public function setCreatedAt(\DateTimeInterface $createdAt): self
{
$this->createdAt = $createdAt;
return $this;
}
public function getContent(): ?string
{
return $this->content;
}
public function setContent(string $content): self
{
$this->content = $content;
return $this;
}
public function getAuthor(): ?User
{
return $this->author;
}
public function setAuthor(?User $author): self
{
$this->author = $author;
return $this;
}
}
我得到一个空数组
编辑3:
我直接从DrawingController添加了一个新的绘图:
/**
* show a drawing
*
* @Route("/dessin/{slug}", name="drawing_show")
*
* @return Response
*/
public function show(Dessin $drawing, CommentDrawingRepository $repo, DessinRepository $repoDrawing, UserRepository $repoUser, ObjectManager $manager)
{
$drawing = $repoDrawing->findAll()[0];
$user = $repoUser->findAll()[0];
$comment = new CommentDrawing();
$comment->setCreatedAt(new \DateTime())
->setContent("un test")
->setAuthor($user)
->setDrawing($drawing);
$manager->persist($comment);
$manager->flush();
$comments = $repo->findAll();
dump($comments);
return $this->render('drawings/show.html.twig', [
'drawing' => $drawing
]);
}
这起作用了。注释在数据库中注册,转储显示注释,注释显示在我的页面中
我试图理解为什么添加了phpmyadmin的评论不起作用,这是多么令人惊讶:两个评论之间的区别在于添加了phpmyadmin的评论将commentdrawing作为判定者值,而添加了doctrine的评论仅作为值。。。这是抽象类的值!我认为鉴别器的价值是有用的告诉学说什么列考虑,我不明白了…但问题解决了。谢谢你的帮助
注:第二个是有效的。。。为什么?关联本身很可能是执行此抽象的错误位置。无论如何,您可能在寻找的是继承映射 供参考: 一表解决方案: 一种选择是执行单表继承。父类获取一个方法getSubject,子类重写该方法并保存userid+评级+注释文本。子类是DrawingComment等,每个子类都与注释的主题有一对一的关联 优点:简单、清晰的语义,如果需要,可以通过类名或额外的函数/属性进行区分,引用完整性稳定,有点容易进行统计,无论注释主题类型如何都可以搜索 缺点:鉴别器列使用起来有点笨拙,并且会稍微降低速度 多表解决方案: 离开继承映射,创建抽象类+接口?或trait+接口用于公共代码。将每个注释类型存储在其自己的类/实体/表中。当您不关心注释的类型时,仍然可以使用接口函数干净地处理它 优点:和以前一样-除了可搜索性,没有鉴别器列,因为每个注释类型都有自己的表 缺点:搜索能力略有降低
归根结底,这是一个品味或习惯的问题。它取决于不同注释类型的公共和不同字段。如果除了主题之外,它们都共享相同的字段,我将执行单表继承。它们之间的差异越大,我就越倾向于使用多表解决方案。没有任何规定不能在单个实体中有多个多表关系。因此,它可能不像Jakumi所建议的继承映射那样优雅和干净,但它工作起来却不费吹灰之力。我已经做过这件事了 使用一个注释实体,同时引用多个其他实体的项目。对于我的评论类,我有其他实体的承认和推荐,每个实体都指向多个评论,但承认和推荐在其他方面并不相同,因此我没有理由让它们中的每一个都像Arleigh Hix在对您的问题的评论中所建议的那样扩展某个抽象类。我这样做的原因与您的项目无关,但对我来说效果很好 注释类: 当然,我的录取实体和我的推荐实体也有关系的另一面:
/**
* @ORM\Entity
*/
class Admission
{
public function __construct()
{
$this->comments = new ArrayCollection();
}
/**
* @ORM\OneToMany(targetEntity="Comment",
* mappedBy="admission",
* )
*/
private $comments;
}
非常感谢您详细而全面的回复!我正在阅读所有这些,一旦我熟悉了这个概念,我会尝试一下。我试着用了整个下午和晚上,但我被卡住了。我无法从图纸上得到评论,所以我不确定它是否有效,我也不知道我会做错什么。我编辑了我的第一条消息以显示更改、代码和问题。有什么想法吗?@fred你的discriminatormap关闭了,注释本身不应该在其中——如果它是一个有点抽象的父类——两个类不应该有相同的值comment+CommentDrawing都有注释。其次,子类不应重复字段父类的id应为受保护的,而不是私有的。Ehymels解决方案可能是另一个更简单的选择。我会创建一个有注释的基本artwork类,每种类型的artwork都会扩展该类,@Jakumi解释了扩展实体的不同方法,但建议使用不同的注释类型。从逻辑上讲,你有一个评论类型和许多艺术品类型,所以艺术品应该是扩展实体,谢谢你的回答。我已经修改了我的整个代码以生成不同类型的注释,所以我将首先尝试管理它,但是如果我不能,我将稍后尝试使用不同类型的艺术品,这很有意义。@fred a PersistentCollection with initialized:false是一个延迟加载的集合,通常还没有加载,这实际上并没有给你任何关于它是否有效的信息。在未初始化的集合上调用->toArray之类的函数!,要触发加载,请转储父对象和/或集合。。。或者dump collection->toArray^^@fred也可以使用inherit_data form选项进行查找。我不知道存在…tbh我实际上也考虑过你的解决方案,对我来说反对它的唯一原因是,它不可搜索,从技术上讲,你可以对两个以上不同类型的主题发表一条评论。不过,您可以用代码和一个真正由代码管理的鉴别器列来修复所有这些问题。事实上,创建的表几乎与单表继承(取决于鉴别器列^^)完全相同。这就是为什么我最终没有去做。。。。。不过,解决办法是好的。
<?php
namespace App\Controller;
use App\Entity\Dessin;
use App\Form\DrawingType;
use App\Entity\CategorieDessin;
use App\Service\PaginationService;
use App\Repository\DessinRepository;
use App\Repository\CategorieDessinRepository;
use Symfony\Component\HttpFoundation\Request;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class DrawingsController extends AbstractController
{
// I hide the rest of the code because it's useless
/**
* show a drawing
*
* @Route("/dessin/{slug}", name="drawing_show")
*
* @return Response
*/
public function show(Dessin $drawing)
{
dump($drawing);
die();
return $this->render('drawings/show.html.twig', [
'drawing' => $drawing
]);
}
}
/**
* show a drawing
*
* @Route("/dessin/{slug}", name="drawing_show")
*
* @return Response
*/
public function show(Dessin $drawing, CommentDrawingRepository $repo)
{
$comments = $repo->findAll();
dump($comments);
die();
return $this->render('drawings/show.html.twig', [
'drawing' => $drawing
]);
}
/**
* show a drawing
*
* @Route("/dessin/{slug}", name="drawing_show")
*
* @return Response
*/
public function show(Dessin $drawing, CommentDrawingRepository $repo, DessinRepository $repoDrawing, UserRepository $repoUser, ObjectManager $manager)
{
$drawing = $repoDrawing->findAll()[0];
$user = $repoUser->findAll()[0];
$comment = new CommentDrawing();
$comment->setCreatedAt(new \DateTime())
->setContent("un test")
->setAuthor($user)
->setDrawing($drawing);
$manager->persist($comment);
$manager->flush();
$comments = $repo->findAll();
dump($comments);
return $this->render('drawings/show.html.twig', [
'drawing' => $drawing
]);
}
/**
* @ORM\Entity
*/
class Comment
{
/**
* @ORM\Column(type="text")
*/
private $comment;
/**
* @ORM\ManyToOne(
* targetEntity="App\Entity\Referral",
* inversedBy="comments"
* );
*/
private $referral;
/**
* @ORM\ManyToOne(
* targetEntity="App\Entity\Admission",
* inversedBy="comments"
* );
*/
private $admission;
// getters and setters omitted
}
/**
* @ORM\Entity
*/
class Admission
{
public function __construct()
{
$this->comments = new ArrayCollection();
}
/**
* @ORM\OneToMany(targetEntity="Comment",
* mappedBy="admission",
* )
*/
private $comments;
}