Учение2 OneToMany вставляет NULL в качестве внешнего ключа

У меня есть двунаправленные отношения OneToMany с использованием Doctrine 2 в качестве ORM в ZendFramework 1.11.2.

Примечание. Doctrine не создавала таблицы базы данных. База данных — MySQL.

По какой-то причине, когда я сохраняю и сбрасываю новый объект ссылки в таблицу ссылок (см. ниже), для поля внешнего ключа (container_id) устанавливается значение NULL. Однако если удалить символ @ из строки ManyToOne(targetEntity="Shepherd\Navigation\Domain\Container\Model", inversedBy="links")', поле внешнего ключа будет заполнено правильно.

Поскольку объект правильно добавляется в базу данных, когда символ «@» удаляется, где-то что-то не так с отношением OneToMany.

Например, если у меня есть модель ссылки с именем $link (см. псевдокод ниже)...

 $link (Shepherd\Navigation\Domain\Link\Model) 
    {
        id:   ''      // auto generated value
        cid:  23      // the foreign key value
        label: test   
        uri: test.com 
        ...           // other values not listed here for brevity
    }

... когда новая модель ссылки сохраняется и диспетчер сущностей сбрасывается, значение container_id (внешний ключ) из недавно вставленной строки в таблице ссылок (shepherd_navigation_link) равно NULL.

    $em // Assume $em is the Entity Manager
    $em->persist($link);
    $em->flush();

    // The container_id in the newly added row in the 
    // link table (shepherd_navigation_link) is NULL 

Схема таблицы ссылок:

CREATE TABLE `shepherd_navigation_link` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `container_id` int(10) unsigned DEFAULT NULL,
  `node_id` int(10) unsigned DEFAULT NULL,
  `parent_id` int(10) unsigned DEFAULT NULL,
  `label` varchar(100) NOT NULL,
  `options` text,
  `events` text,
  `privilege` varchar(100) NOT NULL,
  `resource` varchar(100) DEFAULT NULL,
  `uri` varchar(300) NOT NULL,
  `visible` int(10) unsigned DEFAULT '1',
  PRIMARY KEY (`id`),
  KEY `container_id` (`container_id`)
) ENGINE=InnoDB
ALTER TABLE `shepherd_navigation_link` ADD FOREIGN KEY (container_id) REFERENCES shepherd_navigation_container(id)

Модель объекта ссылки:

/**
 * @Entity
 * @Table(name="shepherd_navigation_link")
 */
class
{
    /** 
     * @Id 
     * @Column(type="integer")
     * @GeneratedValue 
     */
     protected $id;

    /** 
     * @Column(name="container_id", type="integer", nullable=false)
     */
     protected $cid;

    /** 
     * @Column(name="node_id", type="integer")
     */
    protected $nid;

    /** 
     * @Column(name="parent_id", type="integer", nullable=false)
     */
    protected $pid;

    /** 
     * @Column
     */
    protected $label;

    /** 
     * @Column(nullable=true)
     */
    protected $options;

    /** 
     * @Column(nullable=true)
     */
    protected $events;

    /** 
     * @Column
     */
    protected $privilege;

    /** 
     * @Column(nullable=true)
     */
    protected $resource;

    /** 
     * @Column
     */
    protected $uri;

    /** 
     * @Column(type="integer", nullable=true)
     */
    protected $visible;

    /**
     * @OneToMany(targetEntity="Model", mappedBy="parent")
     */
    private $children;

    /**
     * @ManyToOne(targetEntity="Model", inversedBy="children")
     */
    private $parent;

    /**
     *) @ManyToOne(targetEntity="Shepherd\Navigation\Domain\Container\Model", inversedBy="links"
     */
    private $container;

    /**
     * @OneToOne(targetEntity="Shepherd\Navigation\Domain\Link\Position", inversedBy="link")
     */
    private $node;

    public function __construct()
    {
        $this->children = new \Doctrine\Common\Collections\ArrayCollection();   
    }

    /** Accessors and Mutators excluded for brevity **/
}

Примечание. Защищенное свойство $cid сопоставляется с столбцом container_id выше.

Схема контейнерной таблицы:

CREATE TABLE `shepherd_navigation_container` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL,
  `description` text,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB

Сущностная модель контейнера:

/**
 * @Entity
 * @Table(name="shepherd_navigation_container")
 */
class Model
{
    /** 
     * @Id 
     * @Column(type="integer")
     * @GeneratedValue 
     */
    protected $id;

    /** 
     * @Column
     */
    protected $name;

    /** 
     * @Column(nullable=true)
     */
    protected $description;

    /**
     * @OneToMany(targetEntity="Shepherd\Navigation\Domain\Link\Model", mappedBy="container")
     */
    private $links;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->links = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /** Accessors and Mutators excluded for brevity **/
}

Что мне не хватает? Что я делаю неправильно?


person user175590    schedule 16.03.2011    source источник
comment
Я не верю, что вам нужен полный путь к вашим целевым объектам в сопоставлении ассоциаций. Похоже, что на некоторых у вас есть весь путь, а на других — только имя сущности. Я не уверен, что это является причиной проблемы, но это то, на что вы могли бы обратить внимание.   -  person Jeremy Hicks    schedule 18.03.2011
comment
Спасибо, Джереми, ты прав. Я непоследовательно называю модели. Но проблема все еще сохраняется.   -  person user175590    schedule 22.03.2011


Ответы (1)


Я понял проблему (прочитав документацию http://www.doctrine-project.org/docs/orm/2.0/en/tutorials/getting-started-xml-edition.html). Оказывается, проблем действительно было немного.

Проблема 1 => Я не предоставил метод для установки переменной контейнера.

// Inside the Link Entity class...

public function setContainer($container)
{
    $this->container = $container;
}

Проблема 2 => Я не установил значение контейнера. По ошибке я думал, что Doctrine 2 делает это внутри, но я обнаружил, что переменная контейнера должна быть установлена ​​до сброса.

Глупая оплошность с моей стороны.

$link = new Link();
$link->setContainer($container);

// $em is the Entity Manager
$em->persist($link);
$em->flush();

Проблема 3 => Контейнер ($container) должен быть либо сохранен до сброса, либо необходимо изменить определение @OneToMany объекта контейнера. Я решил обновить определение сущности контейнера. Посмотрите здесь (http://www.doctrine-project.org/docs/orm/2.0/en/reference/working-with-associations.html#transitive-persistence-cascade-operations) для получения дополнительной информации.

// Inside the Container Entity class...
/**
 * @OneToMany(targetEntity="Shepherd\Navigation\Domain\Link\Model", mappedBy="container", cascade={"persist"})
 */

После внесения этих изменений и удаления отношения узла @OneToOne в классе сущности ссылки (как оказалось, мне это не нужно) все заработало нормально. Я надеюсь, что это помогает кому-то.

person user175590    schedule 22.03.2011