我有一个'person'实体与'city'实体有很多关系:
这是人物的关系映射:
/**
* @ORM\ManyToOne(targetEntity="City", inversedBy="persons", cascade={"persist"})
*/
private $city;
和城市:
/**
* @ORM\OneToMany(targetEntity="Person", mappedBy="city")
*/
private $persons;
我使用由doctrine生成的基本Symfony 2'人'控制器: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');
}
}
当我提交表单时,由于cascade = {“persist”},所以创建了Person实体以及City实体。
当我用DB中已存在的城市名称填写表单时,问题就出现了,Doctrine创建了另一个具有相同城市名称的条目。
Doctrine是否有一种简单的方法可以检测到它,并使用Person表中的现有city_id?
答案 0 :(得分: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();
}
答案 1 :(得分:2)
正如@vadim所说,你必须使用datatransformer。它可能会在开始时混乱,但在大约30分钟后你会学到它。请记住,在世界各地,您将拥有许多同名的城市。
最好的解决方案就是这样;在该文本字段中,用户可以输入类似Belgrade, Montana, Usa
的名称(顺便说一下;贝尔格莱德是塞尔维亚的首都,只是给你一个同名城市的例子)。 Datatransformer将读取DB并找到您可以链接的正确的贝尔格莱德市。
执行此操作后(并且非常简单),您可以为该字段构建自动完成功能。 @artworkad建议过于复杂,以后会带来更多问题。