简体   繁体   English

symfony3:为具有多对一关系的列的实体创建表单

[英]symfony3: create form for entity that has a column with many to one relationship

I have a "Tasks" table that references a "Estados" table with a foreign key from column Tasks.taskestado to Estados.estado. 我有一个“任务”表,引用一个“Estados”表,其中包含从Tasks.taskestado列到Estados.estado的外键。

Here's the relevant XML mapping for Tasks: 这是任务的相关XML映射:

<entity name="AppBundle\Entity\Tasks" table="TASKS" repository-class="AppBundle\Repository\TasksRepository">
<id name="taskid" type="bigint" column="TaskID">
  <generator strategy="IDENTITY"/>
</id>
...
<many-to-one field="taskestado" target-entity="Estados" fetch="LAZY">
  <join-columns>
    <join-column name="TaskEstado" referenced-column-name="Estado"/>
  </join-columns>
</many-to-one>
...

And for Estados: 而对于Estados:

<entity name="AppBundle\Entity\Estados" table="ESTADOS">
<id name="estado" type="string" column="Estado" length="15">
  <generator strategy="IDENTITY"/>
</id>
<field name="estadodescricao" type="string" column="EstadoDescricao" length="50" nullable="true">
  <options>
    <option name="fixed"/>
  </options>
</field>
...

Given this, I'm trying to make an action (novaAction()) to create tasks. 鉴于此,我正在尝试创建一个动作(novaAction())来创建任务。 Here's the Controller code: 这是Controller代码:

public function novaAction(Request $request)
{
    $task = new Tasks();
    $em = $this->getDoctrine()->getManager();

    dump($task);
    #$task->setTaskEstado(new Estados());
    $form = $this->createForm(TasksType::class, $task);
    $form->handleRequest($request);

    if ($form->isSubmitted()) {
        if ($form->isValid()) {
            // Criar a tarefa na BD
            $em->persist($form->getData());
            $em->flush();
            $this->addFlash('notice', 'app.nova_tarefa.mensagem_sucesso');

            return $this->redirectToRoute('nova_tarefa');
        }

        $this->addFlash('error', 'app.nova_tarefa.mensagem_erro');
    }

And the relevant TasksType code: 以及相关的TasksType代码:

class TasksType extends AbstractType
{

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('taskid', HiddenType::class)
        ...
        #->add('taskestado')
        ->add('taskestado', EntityType::class, [ 'class' => 'AppBundle:Estados' ])
        ...
}

/**
 * @param OptionsResolver $resolver
 */
public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults(array(
        'data_class' => 'AppBundle\Entity\Tasks',
        #'empty_data' => function (\Symfony\Component\Form\FormInterface $form) {
        #    #return new Tasks($form->get('tasks')->getData());
        #    return new Tasks();
        #},
    ));
}
}

The 'empty_data' option was an attempt to create the form without passing an instance of Tasks to it. 'empty_data'选项是尝试创建表单而不向其传递任务实例。 Also, I have the same result when I add taskestado with the commented code, ie, without arguments. 另外,当我使用注释代码添加taskestado时,我也有相同的结果,即没有参数。

And here's the relevant Tasks entity: 这是相关的任务实体:

namespace AppBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;

/**
 * Tasks
 */
class Tasks
{
    /**
     * @var integer
     */
    protected $taskid;

    /**
     * @var \AppBundle\Entity\Estados
     */
    protected $taskestado;

    ...

    /**
     * Get taskid
     *
     * @return integer
     */
    public function getTaskid()
    {
        return $this->taskid;
    }

    /**
     * Set taskestado
     *
     * @param \AppBundle\Entity\Estados $taskestado
     *
     * @return Tasks
     */
    public function setTaskestado(\AppBundle\Entity\Estados $taskestado = null)
    {
        $this->taskestado = $taskestado;

        return $this;
    }

    /**
     * Get taskestado
     *
     * @return \AppBundle\Entity\Estados
     */
    public function getTaskestado()
    {
        return $this->taskestado;
    }

    ...
}

When I open the page, I get the following error: 当我打开页面时,出现以下错误:

Entities passed to the choice field must be managed. 必须管理传递到选择字段的实体。 Maybe persist them in the entity manager? 也许坚持他们在实体经理?

I'd also generated the CRUD ( bin/console doctrine:generate:crud --filter=Tasks ), so that I could check how it's done, but the code is similar, as well as the results (after fixing some issues in the TasksType for some datetime columns). 我还生成了CRUD( bin/console doctrine:generate:crud --filter=Tasks ),这样我就可以检查它是如何完成的,但代码是相似的,以及结果(在修复了一些问题之后)某些日期时间列的TasksType)。

What am I doing wrong? 我究竟做错了什么?

As the error says, you need to set cascade = persist in your mappings for Tasks. 如错误所示,您需要在任务的映射中设置cascade = persist。 For example: 例如:

<many-to-one field="taskestado" target-entity="Estados" fetch="LAZY">
  <cascade>
     <cascade-persist/>
  </cascade>
  <join-columns>
    <join-column name="TaskEstado" referenced-column-name="Estado"/>
  </join-columns>
</many-to-one>

Also Instead of doing $em->persist($form->getData()); 而不是做$em->persist($form->getData()); Use $em->persist($task); 使用$em->persist($task);

See if that works... 看看是否有效......

I finally got an answer to this, it was far from obvious. 我终于得到了答案,这远非显而易见。

As I've said in the question, there's a many-to-one relationship from Tasks.taskestado to Estados.estado. 正如我在问题中所说,从Tasks.taskestado到Estados.estado之间存在多对一的关系。 Estados.estado is a string, that can be nullable, an empty string or (normally) a non-empty string. Estados.estado是一个字符串,可以为空,空字符串或(通常)非空字符串。 Although not indicated in the mapping, the empty string is the default value for taskestado. 虽然未在映射中指出,但空字符串是taskestado的默认值。

I already have data on the table, and one of the entries for Estados.estado is precisely the empty string. 我已经在表上有数据,并且Estados.estado的一个条目恰好是空字符串。

I didn't post in the question, but I saw the following information in the stack trace of this exception: 我没有在问题中发帖,但我在此异常的堆栈跟踪中看到了以下信息:

[1] Symfony\Component\Form\Exception\RuntimeException: Entities passed to the choice field must be managed. Maybe persist them in the entity manager?
    at n/a
        in /var/www/simpletask2/vendor/symfony/symfony/src/Symfony/Bridge/Doctrine/Form/ChoiceList/IdReader.php line 119

    at Symfony\Bridge\Doctrine\Form\ChoiceList\IdReader->getIdValue(object(Estados))
        in  line 

    at call_user_func(array(object(IdReader), 'getIdValue'), object(Estados))
        in /var/www/simpletask2/vendor/symfony/symfony/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php line 204

    at Symfony\Component\Form\ChoiceList\ArrayChoiceList->flatten(array(object(Estados), object(Estados), object(Estados), object(Estados), object(Estados), object(Estados), object(Estados), object(Estados)), array(object(IdReader), 'getIdValue'), array(), array(), array())
        in /var/www/simpletask2/vendor/symfony/symfony/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php line 91

So, the EntityType retrieved the values from the database and was trying to render them. 因此,EntityType从数据库中检索值并尝试呈现它们。 In other words, they were already persisted and the problem could not really reside in how I initialized the entity. 换句话说,它们已经存在,问题实际上并不在于我如何初始化实体。

So, I remembered about the empty string value for the Estados entity, and tried to remove it from the database: problem solved, the TaskEstado entity was initialized and rendered as expected. 所以,我记得Estados实体的空字符串值,并试图将其从数据库中删除:问题解决后,TaskEstado实体被初始化并按预期呈现。

Now I need a way to work around this, but the solution was found. 现在我需要一种解决方法,但找到了解决方案。

Thank all for your answers. 感谢大家的回答。

Make sure the you have 确保你拥有

$this->taskestado = new ArrayCollection();

in the __construct() of your Tasks class. 在您的Tasks类的__construct()中。

Then 2 notices: 然后2个通知:

Try to only use english in your code. 尽量只在代码中使用英语。 This way you get much more responses. 通过这种方式,您可以获得更多响应 As a "best practise" use Singulars for your entity class names Like Task , TaskEstado 作为“最佳实践”,使用Singulars作为您的实体类名称Like TaskTaskEstado

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM