Symfony Doctrine2带外键的复合键-嵌入表单问题
让我们考虑以下场景 我有这些实体Symfony Doctrine2带外键的复合键-嵌入表单问题,symfony,doctrine-orm,Symfony,Doctrine Orm,让我们考虑以下场景 我有这些实体 class RoomI18N { /** * @ORM\Id * @ORM\ManyToOne(targetEntity="TextType") * @ORM\JoinColumn(name="text_type_id", referencedColumnName="id") */ protected $text_type; /** * @ORM\Id * @ORM\ManyT
class RoomI18N
{
/**
* @ORM\Id
* @ORM\ManyToOne(targetEntity="TextType")
* @ORM\JoinColumn(name="text_type_id", referencedColumnName="id")
*/
protected $text_type;
/**
* @ORM\Id
* @ORM\ManyToOne(targetEntity="Language")
* @ORM\JoinColumn(name="language_id", referencedColumnName="id")
*/
protected $language;
/**
* @ORM\id
* @ORM\ManyToOne(targetEntity="Room", inversedBy="room_i18n")
*/
protected $room;
[...]
}
及
如您所见,RoomI18N
entity有一个由其他表(实体)的三个主键组成的复合键。在设计数据库时,这是一种非常常见的处理方法,它还可以节省“空间”,因为我不需要存储我不需要的额外字段(id)。此外,数据复制是最低要求,RoomI18N
(复合)密钥不会存储在表的其他位置
说到这里,我遇到了麻烦,因为RoomI18N
是关系的拥有方,我已经为roome
实体创建了一个表单,在这里我可以-或者不可以-为i18n插入一些文本信息。当我将请求绑定到表单并持久化
Room
对象时,我收到返回的错误(*故意放在那里)
app.ERROR:*******中的异常:类型为******\Entity\RoomI18N的实体
缺少为字段“房间”指定的ID。标识符生成
此实体的策略要求在
调用EntityManager#persist()。如果要自动生成
相反,您需要调整元数据映射
因此。[][]
我很清楚发生了什么:条令试图将RoomI18N
对象保留在room对象之前,因此,room
对象仍然没有ID
好的,如果出现以下情况,我如何摆脱这种情况:
- 我希望避免ID字段作为
主键RoomI18N
- 我不想做一些“奇怪”的黑客行为,比如:从房间对象中删除
相关对象,将其持久化,将其再次放入原始RoomI18N
对象中,并将其再次持久化到DB中Room
cascade
hook和persist对象-只是为了尝试,我确信这不会起作用-当然没有任何改变
更新 I控制器I设置所有
RoomI18N
如下
$handled_languages = $lodging->getHandledLanguages();
[...]
foreach ($handled_languages as $language) {
$room_text_i18n = new RoomI18N();
$room_text_i18n->setLanguage($language);
[...]
$room->addRoomI18n($room_text_i18n); //fetched before
}
$handled_languages = $lodging->getHandledLanguages();
[...]
foreach ($handled_languages as $language) {
$room_text_i18n = new RoomI18N();
$room_text_i18n->setLanguage($language);
[...]
$room->addRoomI18n($room_text_i18n); //fetched before
$room_text_i18n->setRoom($room);
}
public function addRoomI18n(RoomI18N $roomI18n)
{
$this->room_i18n[] = $roomI18n;
$roomI18n->setRoom($this); //As is the owning side, I need to set it explicitly otherwise I need to set everytime
//I want to persist a Room object
return $this;
}
好的,我找到了解决办法。
我需要显式地将反转的side对象(
Room
)设置为拥有side one(RoomI18N
)
基本上我改变了我的控制器的代码如下
$handled_languages = $lodging->getHandledLanguages();
[...]
foreach ($handled_languages as $language) {
$room_text_i18n = new RoomI18N();
$room_text_i18n->setLanguage($language);
[...]
$room->addRoomI18n($room_text_i18n); //fetched before
}
$handled_languages = $lodging->getHandledLanguages();
[...]
foreach ($handled_languages as $language) {
$room_text_i18n = new RoomI18N();
$room_text_i18n->setLanguage($language);
[...]
$room->addRoomI18n($room_text_i18n); //fetched before
$room_text_i18n->setRoom($room);
}
public function addRoomI18n(RoomI18N $roomI18n)
{
$this->room_i18n[] = $roomI18n;
$roomI18n->setRoom($this); //As is the owning side, I need to set it explicitly otherwise I need to set everytime
//I want to persist a Room object
return $this;
}
暗示来自:
更新 如前所述,最好修改
addRoomI18n()
函数(Room
实体,因此反向侧)如下
$handled_languages = $lodging->getHandledLanguages();
[...]
foreach ($handled_languages as $language) {
$room_text_i18n = new RoomI18N();
$room_text_i18n->setLanguage($language);
[...]
$room->addRoomI18n($room_text_i18n); //fetched before
}
$handled_languages = $lodging->getHandledLanguages();
[...]
foreach ($handled_languages as $language) {
$room_text_i18n = new RoomI18N();
$room_text_i18n->setLanguage($language);
[...]
$room->addRoomI18n($room_text_i18n); //fetched before
$room_text_i18n->setRoom($room);
}
public function addRoomI18n(RoomI18N $roomI18n)
{
$this->room_i18n[] = $roomI18n;
$roomI18n->setRoom($this); //As is the owning side, I need to set it explicitly otherwise I need to set everytime
//I want to persist a Room object
return $this;
}
您可以在主实体中添加外键实体的同时添加主键实体实例,如下所示:
public function addRoomI18n(RoomI18n $RoomI18n)
{
$this->RoomI18n[] = $RoomI18n;
$RoomI18n->setRoom($this);
return $this;
}
Room::addRoomI18n()
是否也在传递的RoomI18N上设置房间?类似于public function addRoomI18N(RoomI18N$RoomI18N){$this->RoomI18N->add($RoomI18N);$RoomI18N->setRoom($this);}
。啊,我看你已经弄明白了:)@JasperN.brower:你的方向是对的,看看下面我的答案,我仍然建议你使用room::addRoomI18N()
方法来处理这个问题。这样你就不会在其他地方忘记它(比如控制器)。@JasperN.Brouwer:当然可以。我只是根据我的问题提出了“最快”的解决方案:)我已经在addRoom18n函数中使用过了是的,这正是我所做的,如果你阅读评论(3小时前!!)你会注意到我答案中的代码片段是这样写的,因为问题是这样写的,我不会修改整件事,但贾斯珀对你说了同样的话,我同意。对我来说,这个问题不需要考虑,应该删除。别担心:)顺便说一句,我已经更新了我自己的答案。我想从现在起,所有人都会明白:)