插入具有关联的实体时,有没有办法只使用 FK 而不是检索实体?

Posted

技术标签:

【中文标题】插入具有关联的实体时,有没有办法只使用 FK 而不是检索实体?【英文标题】:When inserting an entity with associations, is there a way to just use the FK instead of retrieving the entity? 【发布时间】:2011-07-19 22:11:15 【问题描述】:

我需要插入一个具有关联的实体。

如果我已经拥有关联实体的 FK,有没有办法将主实体插入到数据库中,只填充 FK?

或者我总是必须这样做

通过 FK 检索关联实体, 填充引用关联的主要实体的属性, 然后调用persist方法。

【问题讨论】:

那么你想通过指定一个现有实体的ID来手动创建一个关系?您能否添加一些您想要实现的示例代码? 嘿 Cobby,感谢您的回复。我有一个创建用户表单,您可以在其中从选择选项列表中选择要赋予用户的角色(在这种情况下,用户只能拥有一个角色)。所以当我处理表单提交时,我应该有一个用户名和一个roleId。如果我想保存用户,是否需要检索关联的角色实体并将其设置在我的用户对象中以保存用户对象?或者我可以简单地在用户对象中设置 roleId 并保存它? 【参考方案1】:

您可以使用 entityManager::merge 完成此操作

$post = new Post();
$post->setPostCategory(['id' => 1]);
$em->persist($em->merge($post));
$em->flush();

【讨论】:

对我不起作用:传递给 App\Entity\Post::setPostCategory() 的参数 1 必须是 App\Entity\PostCategory 的实例或 null,给定数组【参考方案2】:

你想要一个reference proxy

假设我有帖子和标签。一个帖子有很多标签。我从用户那里得到了一堆标签,他们检查了一堆复选框。

以下内容会在现有帖子中添加标签,而不是先获取每个标签实体。它通过使用由EntityManager::getReference() 生成的参考代理来做到这一点:

$tag_ids = $_POST['tag_id']; // an array of integers representing tag IDs.
$post = $em->getRepository('Post')->find($post_id); // returns a Post entity.

foreach($tags_ids as $tid)
   $post->addTag($em->getReference('Tag',$tid));

$em->persist($post);
$em->flush();

【讨论】:

啊,明白了,这很有意义,但是后端实际发生了什么?当学说用新添加的标签持久化帖子时,它最终是否会用实际实体替换代理,然后将这些关联添加到连接表中? 我不确定 Doctrine 在内部做了什么,但我希望它是有效的——它只是根据需要插入和/或更新。如果您使用不存在的 id 创建引用代理,则在尝试 flush() 时可能会遇到异常,并且事务会回滚。但不要相信我的话,自己测试一下。 是的,我会试试看。再次感谢您的时间,timdev,我真的很感激。干杯。 完全不知道 EntityManager::getReference() 函数,超级失败。可能应该更仔细地重新阅读 API 文档:P +1 很棒的回复@timdev。如果 id 不存在,它仍然在生成引用代理,我已经发布了这个问题here。我仍然不明白为什么教义会为不存在的实体生成代理...【参考方案3】:

关于使用参考代理 在我的调查中,这只是部分解决方案,如下所示:

是的,您不必主动检索相关记录(因为您创建了代理记录),但是当您刷新(提交)更新事务时,它仍然首先执行选择语句来检索相关记录,并且然后只进行更新(对数据库一键完成)。 这是低效的,不应该是必要的(我们有外键 id,为什么要检索记录..?)

因此,虽然不是一个完整的解决方案,但您获得的只是与数据库的单个连接(这很好)和稍微简化的代码。

我不确定目前是否有解决方案...?? 希望以后的教条会更新,如果使用代理逻辑,我们应该会自动获得性能增强...

【讨论】:

【参考方案4】:

您应该检索要关联的实体并建立关系。

我假设您可以通过 DBAL 层直接访问数据库来手动指定关系,但我不建议这样做,也没有尝试过。

【讨论】:

Cobby,是的,这正是我所期待的,但为什么不建议这样做,因为它在技术上会节省额外的查询?再次感谢您抽出时间跟进我的问题,非常感谢。 按照您的示例,您应该已经缓存了您的角色(在为下拉列表加载角色时确保在上一个请求中这样做)。所以这并不是一个额外的查询。通过这种方式,您可以维护一个更干净的域层,但代价是性能损失极小。

以上是关于插入具有关联的实体时,有没有办法只使用 FK 而不是检索实体?的主要内容,如果未能解决你的问题,请参考以下文章

是否可以在实体框架中将表FK链接到另外两个PK?

无法插入具有空外键的实体

在实体框架 EDMX 中创建视图之间的关联时出错

实体框架和 FK 问题再次出现

删除可选相关实体时如何将 FK 更新为 null

Hibernate @OneToMany 关联尝试设置空 FK 值