4

这是我的问题:我有 2 个名为“Brand”和“Element”的实体。每个元素都与一个独特的品牌有关。

品牌实体

/**
* 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):

-+--------+----------+-------+
 | ID | name |      model    |
-+--------+----------+-------+
 | 1  | Dell |  Inspiron 14  |
-+--------+----------+-------+
 | 2  | Dell |  Inspiron 15  |
-+--------+----------+-------+
 | 3  | Acer |   Aspire E    |
-+--------+----------+-------+
 | 4  | Dell |  Inspiron 15  |
-+--------+----------+-------+
 | .  |  ..  |      ...      |
-+--------+----------+-------+

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

我考虑过在 PrePersist 函数中调用 EntityManager(如果存在“名称+模型”这对夫妇,则在品牌中搜索,如果是则返回此对象),但根据其他人的说法,这不是一个好的解决方案。

编辑

这是我使用的解决方案:

// 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
    }
}
4

2 回答 2

4

在持久化任何实体之前,您可以将其触发为:

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

    if ($entity == null)
    {
        //no brand found. So, persist the new one:
        ...
    }
    else
    {
        $element->setBrand($theNewBrand);
    }
于 2013-11-06T14:38:40.780 回答
2

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

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

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

于 2013-11-06T14:40:49.033 回答