У меня есть две таблицы:
таблица A с идентификатором в качестве первичного ключа
таблица B с идентификатором в качестве первичного ключа и внешним ключом
Объяснение:
Мне нужно иметь в таблице B первичный ключ, который также должен быть внешним ключом, который указывает на первичный ключ таблицы A.
Может ли кто-нибудь объяснить мне, как сопоставить это с помощью аннотаций в Доктрине 2?
Заметка:
Я попробовал:
class A { /** * @var bigint $id * * @Column(name="id", type="bigint", nullable=false) * @Id * @GeneratedValue(strategy="IDENTITY") */ private $a_id; ...
и B таблица:
class B { /** * @var bigint $id * @Id * @OneToOne(targetEntity="A", fetch="LAZY") * @JoinColumn(name="id", referencedColumnName="id") */ private $b_id; ...
Но это дает мне эту ошибку:
Неотключить исключение «Doctrine \ ORM \ Mapping \ MappingException» с сообщением «Нет идентификатора / первичного ключа, указанного для Entity« B ». Каждый объект должен иметь идентификатор / первичный ключ. ' в /var/www/agr-reg-php/Doctrine/ORM/Mapping/MappingException.php:37 Трассировка стека:
NB: У меня не должно быть составного первичного ключа.
Это возможно после Учения 2.1 :
Идентификация через внешние объекты или производные объекты : теперь вы можете использовать внешний ключ как идентификатор объекта. Это означает использование @Id в ассоциации @ManyToOne или @OneToOne. Вы можете прочитать эту функцию в учебнике .
Наконец, я решил проблему, указав два поля в классе сущности для одного столбца из реальной таблицы. Изменения производятся только в классе B (см. Вопрос для класса A):
class B { /** * @var bigint $id * @Id @Column(name="id", type="bigint", nullable="false") */ private $b_id; /** * @OneToOne(targetEntity="A", fetch="LAZY") * @JoinColumn(name="id", referencedColumnName="id") */ private $a; ...
Фактически все, что я сделал, записывает два поля в моей сущности для одного и того же первичного ключа и внешнего ключа.
Ну, это другое временное решение для вставки:
/** * @Entity * @Table(name="types") */ class Type { /** * @Id * @Column(type="integer") * @GeneratedValue */ private $id; /** * @OneToMany(targetEntity="type\models\Language", mappedBy="type") */ private $languages; /** * @Column(type="string", length = 45,nullable = true) */ private $category; /** * @Column(type="string", length = 1) */ private $status; /** * @Column(type="string", length = 45) */ private $name; /** * @Column(type="datetime", nullable = true) */ private $datedeleted; /** * @Column(type="datetime", nullable = true) */ private $datemodificated; /** * @Column(type="datetime") */ private $dateregistered; public function __construct() { $this->languages = new \Doctrine\Common\Collections\ArrayCollection; $this->status = 1; $this->dateregistered = new \DateTime("now"); } public function id() { return $this->id; } public function category($value = NULL) { if (is_null($value)) return $this->category; else $this->category = $value; } public function name($value = NULL) { if (is_null($value)) return $this->name; else $this->name = $value; } public function status($value = NULL) { if (is_null($value)) return $this->status; else $this->status = $value; } public function datedeleted($value = NULL) { if (is_null($value)) return $this->datedeleted; else $this->datedeleted = $value; } public function datemodificated($value = NULL) { if (is_null($value)) return $this->datemodificated; else $this->datemodificated = $value; } public function dateregistered($value = NULL) { if (is_null($value)) return $this->dateregistered; else $this->dateregistered = $value; } } /** * @Entity * @Table(name="languages") */ class Language { /** * @Id * @Column(name="type_id", type="integer", nullable="false") */ private $language_id; /** * @Id * @ManyToOne(targetEntity="type\models\Type",inversedBy="languages") * @JoinColumn(name="type_id", referencedColumnName="id") */ private $type; /** * @Column(type="string", length = 100, nullable = true) */ private $description; /** * @Id * @Column(type="string", length = 20) */ private $language; public function language_id($value) { $this->language_id = $value; } public function description($value = NULL) { if (is_null($value)) return $this->description; else $this->description = $value; } public function language($value = NULL) { if (is_null($value)) return $this->language; else $this->language = $value; } public function type($value = NULL) { if (is_null($value)) return $this->type; else $this->type = $value; } } $language = new Language; $xtype_id = $this->em->find("Type",1); $language->language_id($xtype_id->id()); $language->type($xtype_id); $language->description($xdescription); $language->language($xlanguage); $this->em->persist($this); $this->em->flush();
эта вставка в классе с внешним ключом и основным ключом на языке
Я мог бы решить проблему, создав поле pk с тем же именем в чужом поле
class B { /** * @var bigint $a_id * @Id @Column(name="a_id", type="bigint", nullable="false") * @ORM\Id * @ORM\GeneratedValue(strategy="IDENTITY") */ private $a_id; /** * @OneToOne(targetEntity="A", fetch="LAZY") * @JoinColumn(name="id", referencedColumnName="id") */ private $a; . . . /** * @var A * * @ORM\OneToOne(targetEntity="A") * @ORM\JoinColumns({ * @ORM\JoinColumn(name="a_id", referencedColumnName="id", unique=true) * }) */ private $a; //...
У меня была та же задача, и экспериментатор нашел это решение:
class A { /** * @Id @Column(type="integer", nullable=false) * @GeneratedValue */ protected $id; /** * @OneToOne(targetEntity="B", inversedBy="a", orphanRemoval=true, cascade={"persist", "remove"}) * @JoinColumn(name="id", referencedColumnName="id") */ protected $b; } class B { /** * @OneToOne(targetEntity="A", mappedBy="b" ) */ protected $user; /** * @Id * @Column(type="integer", nullable=false) * @GeneratedValue */ protected $id; }