Symfony 添加(如果不存在)或检索另一个实体中的实体

Symfony 添加(如果不存在)或检索另一个实体中的实体,symfony,doctrine-orm,Symfony,Doctrine Orm,我的问题是:我有两个实体,分别命名为“品牌”和“元素”。每个元素都与一个独特的品牌相关 品牌实体 /** * Brand * * @ORM\Entity(repositoryClass="Acme\AcmeBundle\Entity\BrandRepository") */ class Brand { /** * @ORM\Column(name="id", type="integer") * @ORM\Id * @ORM\GeneratedValue(s

我的问题是:我有两个实体,分别命名为“品牌”和“元素”。每个元素都与一个独特的品牌相关

品牌实体

/**
* Brand
*
* @ORM\Entity(repositoryClass="Acme\AcmeBundle\Entity\BrandRepository")
*/

class Brand
{
    /**
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $name;

    /**
     * @ORM\Column(name="model", type="string", length=255, nullable=true)
     */
    private $model;
/**
 * Element
 *
 * @ORM\Entity(repositoryClass="Acme\AcmeBundle\Entity\ElementRepository")
 */

class Element
{
    /**
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\Column(name="serial", type="string", length=255)
     */
    private $serial;

    ... others properties ...

    /**
     * @ORM\ManyToOne(targetEntity="Brand", cascade={"persist"})
     * @ORM\JoinColumn(nullable=false)
     */
    private $brand;
元素实体

/**
* Brand
*
* @ORM\Entity(repositoryClass="Acme\AcmeBundle\Entity\BrandRepository")
*/

class Brand
{
    /**
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $name;

    /**
     * @ORM\Column(name="model", type="string", length=255, nullable=true)
     */
    private $model;
/**
 * Element
 *
 * @ORM\Entity(repositoryClass="Acme\AcmeBundle\Entity\ElementRepository")
 */

class Element
{
    /**
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\Column(name="serial", type="string", length=255)
     */
    private $serial;

    ... others properties ...

    /**
     * @ORM\ManyToOne(targetEntity="Brand", cascade={"persist"})
     * @ORM\JoinColumn(nullable=false)
     */
    private $brand;
我创建了一个单一元素形式,它整合了品牌形式:

// src/Acme/AcmeBundle/Form/ElementType.php

/**
 * @param FormBuilderInterface $builder
 * @param array $options
 */
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('brand', new BrandType())
        ->add('mac')
        ->add('ip')
    ;
}
它工作得很好,但每个新元素都会添加一个新品牌,因此我可以在我的表中有重复的产品(例如品牌2和品牌4):

添加新元素时,如何检索已注册的品牌(并将其映射到元素),而不是添加新品牌

我曾考虑过在PrePersist函数中调用EntityManager(如果夫妇“name+model”存在,则在Brand中搜索,如果存在,则返回此对象),但据其他人说,这不是一个好的解决方案

编辑

以下是我使用的解决方案:

// src/Acme/AcmeBundle/Controller/AcmeController.php

public function createAction(Request $request)
{
    $entity = new Element();
    $form = $this->createForm(...);
    $form->handleRequest($request);

    if ($form->isValid()) {

        $brand = $this->getDoctrine()
               ->getRepository('AcmeAcmeBundle:Brand')
               ->findOneBy(array(
                   'name' => $entity->getBrand()->getName(),
                   'model' => $entity->getBrand()->getModel()
                ));
        if($brand)
            $entity->setBrand($brand);

        $em = $this->getDoctrine()->getManager();
        $em->persist($entity);
        $em->flush();

        // Redirect
    }
}

在持久化任何实体之前,您可以通过以下方式触发它:

    $entity = $em->getRepository('Brand')->findOneBy([
        'model' => $model, 
        'name' => $name
    ]);

    if ($entity == null)
    {
        //no brand found. So, persist the new one:
        ...
    }
    else
    {
        $element->setBrand($theNewBrand);
    }

这感觉像是一个人可能会做的事情。然而,我认为这种方法不适用于这种情况,因为在确定现有品牌是否适用之前,必须单独填写两个字段值(品牌名称和型号)

因此,在我看来,最明显的解决方案,虽然不是很优雅,但只是在提交表单时检查并在必要时更新brand对象,然后将新元素持久化(刷新)到数据库中(有关代码详细信息,请参阅@manix的答案,他在我撰写本文时发布了这篇文章!)。如果您在服务中处理业务逻辑,则此逻辑将从控制器直接或间接执行


这种情况下通常使用的另一种方法是使用所有可用的品牌名称和型号预先填充数据库,并提供下拉列表供用户选择。在这种情况下,当品牌名称更改时,必须使用ajax填充模型列表。如果能够找到与特定品牌相关的所有元素很重要,那么这种方法可以防止由于打字错误而导致品牌重复。

您能否将整个代码张贴在您保留新品牌的位置?似乎需要查询数据库才能搜索重复项。Pfff。。。谢谢你,曼尼克斯!我认为使用PrePersist事件是必需的,但它通过控制器可以完美地工作:)让我稍微演示一下..操作。。。我没有看到您编辑的问题/答案。