Symfony2 / Doctrine2 - ManyToOne - 保存反向关系

9

我是Symfony和Doctrine的新手。

我有一个实体“User”和一个实体“Type”。一个用户可以有一个喜欢的类型,而一个类型可以有许多用户将该特定类型作为喜欢。因此,我需要一个多(用户)对一(类型)的关系。

我已经实现了它,并且它工作得很好(大部分情况下)。但有一件事我不明白。

如果我这样做,它就可以工作:

$user = new User();
$type = new Type();

$user->setFavoriteType($type);
$em->persist($user);
$em->persist($type);
$em->flush();

对象被生成并存储到数据库中,favorite_type_id 被正确设置。因此,改变拥有方的位置能够正常工作。但是,如果仅将用户添加到反向方,并刷新实体管理器,则不会设置 favorite_type_id。
$user = new User();
$type = new Type();

$type->getUsers()->add($user); //same with $type->addUser($user);
$em->persist($user);
$em->persist($type);
$em->flush();

为什么呢?它为什么不能从反向方向工作?我真的必须手动设置吗?如果我在类型实体中操纵addUser方法,像"$user->setFavoriteType($this)",它就会工作。但难道这不应该是doctrine的任务吗?
文档说明如下:
当双向关联被更新时,Doctrine只检查其中一个方向进行这些更改。这被称为拥有方的关联。
所以这似乎是想要的行为,是吗?但为什么呢?由于性能?语义原因?
如果有人能向我解释一下或告诉我我做错了什么,我会很高兴。

有趣的问题,我也很好奇这个逻辑背后的选择。 - DonCallisto
http://doctrine-orm.readthedocs.org/en/latest/reference/unitofwork-associations.html - DonCallisto
你能展示相关的实体吗? - ReynierPM
2个回答

3

请查看Doctrine关于级联操作的文档。通过添加cascade={"persist"}并清除缓存(重新构建Doctrine的元数据缓存),您可以快速轻松地开始实现您想要做的事情。


0
这是因为在考虑持久性时,Doctrine将PHP实体直接映射到数据库表。在您的情况下,用户和类型在概念上具有多对一的关系,但在数据库级别上,该关系完全表示在用户表上 - 用户有一个喜欢的类型,因此用户表具有一个“favorite_type_id”列。虽然我们可以认为类型实体具有一组用户,其中它们是最喜欢的,但这本质上也是通过查看用户表来推导出来的,在类型表中没有任何内容。
在Doctrine中设置实体映射告诉Doctrine实体之间的关系,并允许Doctrine为您提供某些方便的访问方法,例如$ type-> getUsers(),但不会更改底层数据的存储方式。如果我使用$user->setFavoriteType,我正在操作具有直接数据库对应关系的数据,但默认情况下,如果我调用$type->addUser,我不是 - 这种调用的主要目的是在没有简单地丢弃对象并再次从DB中获取它们的情况下,使您当前正在使用的水合实体保持最新状态。
当然,你已经看到了可以自定义addUser来调用setFavoriteType,或者像Shon M建议的那样配置级联持久性,使行为更像你期望/想要的方式。从一开始就省略这个功能可能看起来是浪费时间,但我怀疑Doctrine开发人员有意选择以最简单的方式实现所需的功能,同时清晰地记录并提供几种易于替代的方法,以此来迎合每个人的需求。不管你喜欢与否,在数据库中的数据和在PHP中进行后续操作的数据在技术上是不同的,特别是在像Doctrine这样的模型中,数据库活动被推迟直到开发人员请求它,因此尽可能明确所有这些是非常有意义的!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接