【发布时间】:2014-10-14 08:19:26
【问题描述】:
让我们考虑以下场景。
我有这些实体
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;
[...]
}
和
class Room
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
[...]
/**
* @ORM\OneToMany(targetEntity="RoomI18N", mappedBy="room", cascade={"remove", "persist"})
*/
protected $room_i18n;
[...]
}
如您所见,RoomI18N 实体有一个由其他表(实体)的三个主键组成的复合键。当您设计数据库时,这是一种非常常见的方法,这也将节省“空间”,因为我不需要存储我不需要的额外字段(id)。此外,数据复制是最少的,RoomI18N(复合)键不会存储在其他地方的表中。
也就是说,我遇到了麻烦,因为 RoomI18N 是关系的拥有方,我已经为 Room 实体创建了一个表单,我可以(或不能)为 i18n 插入一些文本信息。
当我将请求绑定到我的表单并保留 Room 对象时,我收到了该错误(* 是故意放在那里的)
app.ERROR: ***** 中的异常:类型为 ******\Entity\RoomI18N 的实体 缺少字段“房间”的分配 ID。标识符生成 此实体的策略需要先填充 ID 字段 EntityManager#persist() 被调用。如果要自动生成 标识符,而不是您需要调整元数据映射 因此。 [] []
我很清楚发生了什么事:教义尝试在房间对象 BEFORE 之前保留 RoomI18N 对象,因此,Room 对象仍然没有 ID。
好的,如果出现以下情况,我该如何摆脱这种情况:
- 我希望避免将 ID 字段作为
RoomI18N主键 - 我不希望做一些“奇怪”的黑客攻击,例如:从 Room 对象中删除
RoomI18N相关对象,将其持久化,将它们再次放入原始Room对象并再次将其持久化到 DB
此外,当然,我已经尝试手动删除 cascade 挂钩并持久化对象 - 只是为了尝试,我确信这不会起作用 - 当然没有任何改变。
更新
我控制器我将所有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
}
【问题讨论】:
-
Room::addRoomI18n()是否也将 Room 设置在传递的 RoomI18N 上?类似于public function addRoomI18N(RoomI18N $roomI18N) { $this->room_i18n->add($roomI18N); $roomI18N->setRoom($this); }。 -
啊,我看你已经想通了 :)
-
@JasperN.Brouwer:你的方向是对的,请看下面我的回答
-
我仍然建议您使用
Room::addRoomI18n()方法来解决这个问题。这样你就不会在其他地方忘记它(比如控制器)。 -
@JasperN.Brouwer:是的,当然。我只是根据我的问题提出“最快”的解决方案:) 我已经在 addRoom18n 函数中完成了
标签: symfony doctrine-orm