понимание проблем соотношения в доктрине 2 - PullRequest
9 голосов
/ 25 июля 2010

Я читаю официальную документацию и массу тем, но все еще не могу найти решение для моей ситуации. Мой случай очень прост. У меня есть 2 объекта: комментарии и ключевые слова для них. В одном комментарии может быть много ключевых слов, но каждое ключевое слово предназначено только для одного комментария. Ключевые слова не являются уникальными в таблице ключевых слов. Поэтому я решил, что это отношение один ко многим. Структура таблиц выглядит следующим образом:

ключевые слова

id          int(11)
comment_id  int(11)
text        varchar(30)

комментарии

id      int(11)
text    text

вот как я их отобразил:


/**
 *  @Entity
 *  @Table(name="comments")
 **/
class Comments
{
    /** @Id @Column(type="integer") */
    private $id;
    /** @Column(type="text") */
    private $text;

    /**
     * @OneToMany(targetEntity="keywords", mappedBy="comment_id")
     */
    private $keywords;

    public function getText(){return $this->text;}
    public function getId(){return $this->id;}
    public function getKeywords(){return $this->keywords;}
}
/**
 *  @Entity
 *  @Table(name="keywords")
 */

class Keywords
{
    /** @Id @Column(type="integer") */
    private $id;

    private $text;

    public function getText(){return $this->text;}
    public function getId(){return $this->id;}
}

и как это использовать:


$comments = $this->em->getRepository('comments' )->findAll();
foreach($comments as $comment){
    foreach($comment->getKeywords() as $keyword){
        $keyword->getText();
    }
}

и получил следующие ошибки: Notice: Undefined index: comment_id in C:\web_includes\doctrine\ORM\Persisters\BasicEntityPersister.php on line 1096 Notice: Trying to get property of non-object in C:\web_includes\doctrine\ORM\Persisters\BasicEntityPersister.php on line 1098 Warning: Invalid argument supplied for foreach() in C:\web_includes\doctrine\ORM\Persisters\BasicEntityPersister.php on line 1098 Notice: Undefined index: comment_id in C:\web_includes\doctrine\ORM\PersistentCollection.php on line 168 Fatal error: Call to a member function setValue() on a non-object in C:\web_includes\doctrine\ORM\PersistentCollection.php on line 169 Что случилось? где следует определить comment_id? Правильно ли мое отображение? Я действительно застрял и мне нужна помощь, поэтому, пожалуйста, любые советы очень приветствуются.

1 Ответ

13 голосов
/ 25 июля 2010

Атрибут mappedBy ничего не говорит об имени внешнего ключа, для этого и нужна аннотация "@JoinColumn". Правильное отображение для этого сценария будет:

/**
 *  @Entity
 *  @Table(name="comments")
 **/
class Comments
{
    /** @Id @Column(type="integer") */
    private $id;
    /** @Column(type="text") */
    private $text;

    /**
     * @OneToMany(targetEntity="keywords", mappedBy="comment")
     */
    private $keywords;

    public function getText(){return $this->text;}
    public function getId(){return $this->id;}
    public function getKeywords(){return $this->keywords;}
}

/**
 *  @Entity
 *  @Table(name="keywords")
 */
class Keywords
{
    /** @Id @Column(type="integer") */
    private $id;

    /**
     * @ManyToOne(targetEntity="Comments", inversedBy="keywords")
     */
    private $comment;

    /**
     * @Column(type="text") */
    private $text;

    public function getText(){return $this->text;}
    public function getId(){return $this->id;}
}

Используя Schema Tool, он генерирует SQL, равный вашей схеме:

CREATE TABLE comments (id INT NOT NULL, text LONGTEXT NOT NULL, PRIMARY KEY(id)) ENGINE = InnoDB;
CREATE TABLE keywords (id INT NOT NULL, comment_id INT DEFAULT NULL, text LONGTEXT NOT NULL, PRIMARY KEY(id)) ENGINE = InnoDB;
ALTER TABLE keywords ADD FOREIGN KEY (comment_id) REFERENCES comments(id);

Две проблемы в вашем отображении:

  1. Вы должны понимать разницу между владением и обратной стороной. Простое однонаправленное отношение «один ко многим» требует третьей таблицы соединений. Однако с двунаправленным отношением, как в моем отображении со свойством sideing Keyword :: $ comment, это работает.
  2. "mappedBy" относится к свойству другого targetEntity, которое является "другой стороной этой ассоциации". InversedBy имеет примерно то же значение, только что inversedBy всегда указывается на стороне владельца, mappedBy на обратной стороне.

Все это звучит очень сложно, но это очень эффективный способ с технической точки зрения ORM, поскольку он позволяет обновлять ассоциации с наименьшим количеством требуемых операторов SQL UPDATE. Смотрите документы о том, как работает Inverse / Owning:

http://www.doctrine -project.org / проекты / ОРМ / 2,0 / документы / ссылки / ассоциация-отображение / ан # владеющим стороны-и-обратная сторона

...