Symfony 2中使用Doctrine实现一对多关系

3
我已经在Stack Overflow和其他网站上查看了大量的问题/答案,但是找不到解决这个问题的方法。
在我解释问题之前,我已经:
- 剥离了我的实体,使它们只有最小的属性和方法。 - 清除了Doctrine查询缓存/元数据缓存。 - 删除并重新创建了模式。 - 检查了我的拼写。
我有以下两个实体:
<?php
namespace Docker\ApiBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

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

  /**
   * @ORM\Column(type="integer")
   * @ORM\ManyToOne(targetEntity="Project",inversedBy="sources")
   * @ORM\JoinColumn(referencedColumnName="id")
   */
  private $project;

}


<?php
namespace Docker\ApiBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

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

  /**
   * @ORM\OneToMany(targetEntity="Source", mappedBy="project")
   */
  private $sources;

  public function __construct() {
    $this->sources = new ArrayCollection();
  }

  public function getSources() {
    return $this->sources;
  }
}

因此,多个“源”可以属于一个“项目”。

在我的控制器中,我有:

$em = $this->getDoctrine()->getManager();
$project = $em->find('Docker\ApiBundle\Entity\Project', 1);
$sources = $project->getSources()->toArray();

我尝试了很多方法,但总是遇到这个问题:

Notice: Undefined index: project in /.../www/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php line 1577

就像我所说的,我知道有很多关于这个问题的疑问,但是没有一个被接受的答案可以解决我的问题。

这看起来与使用Doctrine2非常基本,所以我不确定我做错了什么 - 这可能是一些非常明显的错误。

任何帮助都将不胜感激。


$project变量不为空吗?或者在执行->getSources()->toArray()时会崩溃吗? - Sybio
$project变量不为空,是的 - 当我在控制器中执行$sources = $project->getSources()->toArray();时会引发异常。如果我将其删除,则一切正常。 - JonB
2个回答

5

您拥有:

/**
* @ORM\Column(type="integer")
* @ORM\ManyToOne(targetEntity="Project",inversedBy="sources")
* @ORM\JoinColumn(referencedColumnName="id")
*/
private $project;

移除:

@ORM\Column(type="integer")

来自注释。


啊哈!就是这样。这也有道理。谢谢。 - JonB

1
如果这正是你的代码,我没有在你的Project类中看到命名空间。尝试添加命名空间行“namespace Docker\ApiBundle\Entity;”。 如果这是同一个文件夹,则不需要“use”,但如果它是其他包或文件夹的一部分,请尝试在你的Source类中加入一行类似于“use Docker\ApiBundle\Entity\Project;” 的语句。希望能有所帮助... 否则:
<?php
namespace Azimut\ApiBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

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

  private $name;


  /**
   * @ORM\Column(type="integer")
   * @ORM\ManyToOne(targetEntity="Azimut\ApiBundle\Entity\Project", inversedBy="sources")
   * @ORM\JoinColumn(onDelete="CASCADE")
   */
  private $project;


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

/**
 * Set project
 *
 * @param integer $project
 * @return Source
 */
public function setProject($project)
{
    $this->project = $project;

    return $this;
}

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


<?php
namespace Azimut\ApiBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;

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

  /**
   * @ORM\OneToMany(targetEntity="Azimut\ApiBundle\Entity\Source", mappedBy="object", cascade={"all"})
   */
  private $sources;

  public function __construct() {
    $this->sources = new ArrayCollection();
  }

  public function getSources() {
    return $this->sources;
  }

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

/**
 * Add sources
 *
 * @param \Azimut\ApiBundle\Entity\Source $sources
 * @return Project
 */
public function addSource(\Azimut\ApiBundle\Entity\Source $sources)
{
    $this->sources[] = $sources;

    return $this;
}

/**
 * Remove sources
 *
 * @param \Azimut\ApiBundle\Entity\Source $sources
 */
public function removeSource(\Azimut\ApiBundle\Entity\Source $sources)
{
    $this->sources->removeElement($sources);
}
}

控制器的一小部分代码: public function helloAction()

{
        $id = 1;
        $em = $this->getDoctrine()->getManager();
        $project = $em->getRepository('Azimut\ApiBundle\Entity\Project')->find($id);

        $source1 = $em->getRepository('Azimut\ApiBundle\Entity\Source')->find(3);
        $source2 = $em->getRepository('Azimut\ApiBundle\Entity\Source')->find(5);
        $project->addSource($source1);
        $sources = array();
        $sources = $project->getSources();
        var_dump($sources);
        return ....
}

对我来说,这很好用。


很好的发现 - 只是帖子的格式不太对。我已经更新了它,这样命名空间就能显示出来了。 - JonB
好的 - 那太棒了 - 对我来说没问题。然而...我猜像Doctrine这样的库的问题之一就是魔法。它似乎为你做了很多事情,所以我本以为如果我已经用我的项目的源代码填充了数据库,那么我就不需要使用addSource将它们添加到项目实体中了。我猜我可以通过一些postLoad事件回调来自动完成这个操作,但我不确定(考虑到它还做了其他事情)为什么我需要这样做。事实上,我甚至不确定为什么我需要首先设置注解? - JonB
感谢您在这方面的辛勤工作,但是@zelkjo的答案是正确的。在您的回复中,我不得不将源添加到项目中,而在Zeljok的回复中,如果数据库已经预填充,则会返回我所期望的即填充的源实体。我已经给了您+1 - 再次感谢。 - JonB
这取决于你想做什么,我手动添加了一些源和项目,因为以前没有这样的实体。我认为你想将其保留为整数,尽可能使用了你的代码。注释用于映射数据库中的对象。您可以使用注释、yml或xml来设置数据库。如果您对注释不够自信,请使用其他解决方案。 - gerda

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接