如何让 Symfony 2 与学说 ORM 只保留一次相关实体
Posted
技术标签:
【中文标题】如何让 Symfony 2 与学说 ORM 只保留一次相关实体【英文标题】:How to get Symfony 2 with doctrine ORM to persist related entity only once 【发布时间】:2012-10-26 22:48:24 【问题描述】:我有一个与“城市”实体具有多对一关系的“人”实体:
这是人的关系映射:
/**
* @ORM\ManyToOne(targetEntity="City", inversedBy="persons", cascade="persist")
*/
private $city;
和城市的:
/**
* @ORM\OneToMany(targetEntity="Person", mappedBy="city")
*/
private $persons;
我使用由教义生成的基本 Symfony 2 'person' 控制器:generate:crud:
$entity = new Person();
$form = $this->createForm(new PersonType(), $entity);
$form->bind($request);
if ($form->isValid())
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
PersonType 表单类型实例化了一个 CityType
class PersonType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options)
$builder
->add('city', new CityType())
->add('firstname')
->add('lastname')
->add('gender')
...
CityType 表单类型有一个文本字段
class CityType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options)
$builder
->add('cityname', 'text');
当我提交表单时,会创建 Person 实体以及 City 实体,这要归功于 cascade="persist"。
当我使用数据库中已经存在的城市名称填写表单时出现问题,Doctrine 创建另一个具有相同城市名称的条目。
Doctrine 是否有一种简单的方法可以检测到这一点,并使用 Person 表中现有的 city_id?
【问题讨论】:
尝试使用 DataTransformer。检查symfony.com/doc/current/cookbook/form/data_transformers.html我不确定这是否是正确的解决方案。我稍后会尝试并给你反馈 感谢您的建议。这是一个有趣的选择,我目前正在研究它。尽管它没有反映在我上面的问题中,但 City 对象有几个额外的字段来定义它的唯一性:州、国家。我想知道这将如何在数据转换器环境中发挥作用。 【参考方案1】:正如@vadim 所说,您必须使用数据转换器。一开始可能会令人困惑,但大约 30 分钟后你就会学会它。请记住,在世界各地,您将拥有许多同名的城市。
最好的解决方案是这样;在该文本字段中,用户将输入类似Belgrade, Montana, Usa
的名称(顺便说一句;贝尔格莱德是塞尔维亚的首都,只是给您一个具有相同名称的城市示例)。 Datatransformer 将读取 DB 并找到您可以链接的正确的贝尔格莱德城市。
完成此操作后(非常简单),您可以为该字段构建自动完成功能。 @artworkad 建议过于复杂,以后会带来更多问题。
【讨论】:
数据转换器是要走的路,我最终使用了该选项。强大的东西。感谢您的帮助。【参考方案2】:一种解决方案是,不要级联持久化实体。即
if ($form->isValid())
$data = $form->getData();
$em = $this->getDoctrine()->getEntityManager();
$city = $em->getRepository('YourBundle:City')
->findOneByCityname($data['cityname']);
if($city == null)
$city = new City();
$city->setName($data['cityname']);
$em->persist($city);
$em->flush();
$entity->setCity($city);
$em->persist($entity);
$em->flush();
【讨论】:
感谢您的帮助。这可能是我问题的最佳答案。我发现令人惊讶的是,级联系统不允许在“实体存在”类型的场景中指定几个唯一字段。也许我应该把它推荐给 Symfony 的人。以上是关于如何让 Symfony 2 与学说 ORM 只保留一次相关实体的主要内容,如果未能解决你的问题,请参考以下文章