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
    相关对象,将其持久化,将其再次放入原始
    Room
    对象中,并将其再次持久化到DB中
此外,当然,我已经尝试手动删除
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小时前!!)你会注意到我答案中的代码片段是这样写的,因为问题是这样写的,我不会修改整件事,但贾斯珀对你说了同样的话,我同意。对我来说,这个问题不需要考虑,应该删除。别担心:)顺便说一句,我已经更新了我自己的答案。我想从现在起,所有人都会明白:)