>我有几个类使用可标记特征来设置几个教义实体(项目,注释等)通用的标签系统。
这些实体和这些标签之间的关系是多对多的关系,我无法使它多向。
我的问题:当我删除项目实体时,它会从项目表中删除,但project_tag表中此项目与标签之间的关系不会被删除。然后,如果我创建一个新的项目实体,则会引发异常。
An exception exists while executing 'INSERT INTO project_tag (project_id, tag_id) VALUES (?,?)' With params [2, 4]:
SQLSTATE [23000]: Integrity constraint violation: 19 UNIQUE constraint failed: project_tag.project_id, project_tag.tag_id
实体:
标记
/**
* Tag
*
* @ORMTable(name="tag")
* @ORMEntity(repositoryClass="AppBundleRepositoryTagRepository")
*/
class Tag
{
/**
* @var int
*
* @ORMColumn(name="id", type="integer")
* @ORMId
* @ORMGeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORMColumn(name="name", type="string", length=255, unique=true)
*/
private $name;
/**
* @ORMColumn(name="last_use_at", type="datetime", nullable=false)
* @var DateTime
*/
private $lastUseAt;
public function __construct()
{
$this->lastUseAt = new DateTime();
}
public function __toString()
{
return $this->name;
}
/**
* Get id
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* @param string $name
*
* @return Tag
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* @return DateTime
*/
public function getLastUseAt(): DateTime
{
return $this->lastUseAt;
}
/**
* @param DateTime $lastUseAt
*/
public function setLastUseAt(DateTime $lastUseAt)
{
$this->lastUseAt = $lastUseAt;
}
}
可标记
trait Taggable
{
/**
* @var ArrayCollection
*
* @ORMManyToMany(targetEntity="AppBundleEntityTag", cascade={"persist"})
*/
protected $tags;
/**
* Add tag
*
* @param Tag $tag
*
* @return $this
*/
public function addTag(Tag $tag)
{
$tag->setLastUseAt(new DateTime());
$this->tags[] = $tag;
return $this;
}
/**
* Remove tag
*
* @param Tag $tag
*/
public function removeTag(Tag $tag)
{
$this->tags->removeElement($tag);
}
/**
* Get tags
*
* @return DoctrineCommonCollectionsCollection
*/
public function getTags()
{
return $this->tags;
}
}
项目
/**
* Project
*
* @ORMTable(name="project")
* @ORMEntity(repositoryClass="AppBundleRepositoryProjectRepository")
*/
class Project
{
use Taggable;
}
注意
class Note
{
use Taggable;
}
这是唯一的解决方案还是我的注释不完整/不正确? 我尝试使用JoinColumns,JoinTable和onDelete ="级联",但没有任何效果。
与此同时,我回避了这个问题,这个指令放在了支持之前。
$project->getTags()->clear();
控制器中操作的完整代码:
/**
* @Route("/project/{id}/delete", name="project_delete")
*/
public function deleteAction($id) {
$em = $this->getDoctrine()->getManager();
$project = $em->getRepository('AppBundle:Project')->find($id);
if(!$project) {
return $this->redirectToRoute('index');
}
$project->getTags()->clear();
$em->remove($project);
$em->flush();
return $this->redirectToRoute('index');
}
我想我找到了更好的解决方案:您可以在教义配置中设置 PRAGMA。喜欢:
doctrine:
dbal:
# configure these for your database server
driver: 'pdo_sqlite'
#server_version: '5.7'
#charset: utf8mb4
#default_table_options:
#charset: utf8mb4
#collate: utf8mb4_unicode_ci
url: '%env(resolve:DATABASE_URL)%'
options:
'PRAGMA foreign_keys': 'ON'
我刚刚在我的Symfony 4应用程序上尝试了它,重新创建了数据库并使用SQLite的数据库浏览器进行了测试,它按预期工作。
希望这有帮助
我设法解决了这个问题。这是我适用于SQLite连接的解决方案。
创建一个侦听内核请求事件的事件侦听器:
namespace AppBundleEventListener;
use DoctrineBundleDoctrineBundleRegistry;
use DoctrineCommonPersistenceObjectManager;
use SymfonyComponentHttpKernelEventGetResponseEvent;
class RequestListener
{
/**
* @var Registry
*/
private $doctrine;
public function __construct(Registry $doctrine)
{
$this->doctrine = $doctrine;
}
public function onKernelRequest(GetResponseEvent $event)
{
$this->doctrine->getConnection()->exec('PRAGMA foreign_keys = ON');
}
}
服务声明
app.event_listener.request_listener:
class: AppBundleEventListenerRequestListener
arguments:
- '@doctrine'
tags:
- { name: kernel.event_listener, event: kernel.request }
我认为问题是你的特质Taggable
设置为多对多关系的拥有方,但你正在删除相反的一面,并期望结果发生一些事情。教义只会检查关系的拥有方,以保持任何变化。有关此文档,请参阅此处。
你可以通过将Taggable
作为你每个关系的反面来解决,或者通过手动告诉教义删除拥有的一面来解决。
第一个解决方案可能不适合您,因为您不会(轻松)指定多个反边。(你确定特质是正确的方法吗??
第二种解决方案很简单。在 deleteTag($tag) 函数的实体(如Project
)中,调用拥有端的删除函数(例如,deleteProject($project)
.如果不存在,则必须创建。
class Project
{
use Taggable;
public function deleteTag($tag)
{
$this->tags->removeElement($tag);
// persist on the owning side
$tag->deleteProject($this);
}
}
编辑:
看到完整代码后,您似乎正在正确删除。现在你需要告诉教义来贯彻它。有关完整的详细信息,请参阅此帖子,但基本上您可以将您的特征更改为:
trait Taggable
{
/**
* @var ArrayCollection
*
* @ORMManyToMany(
* targetEntity="AppBundleEntityTag",
* cascade={"persist"},
* onDelete="CASCADE"
* )
*/
protected $tags;
// ...
}