Symfony2 Doctrine2 多对多表单不保存实体

22

我在处理多对多关系时遇到了一些问题。我有UsersAssets。我想能够在资产页面上为资产分配用户。

下面的代码在创建/编辑资产时显示用户列表,但更改用户复选框不会保存,而其余数据将被保存。

如果我通过MySQL客户端向users_assets添加条目,则这些更改将显示在资产列表中。

用户

class User extends BaseUser
{
    /**
     * @ORM\ManyToMany(targetEntity="Asset", inversedBy="users")
     */
    private $assets;
}

资产

class Asset
{
    /**
     * @ORM\ManyToMany(targetEntity="User", mappedBy="assets")
     */
    private $users;
}

资产类型

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $form = $builder
        ->add('users', null, array(
            'expanded' => true,
            'multiple' => true
        ))
        ->getForm();

    return $form;
}

你难道不应该将 null 改为 EntityType 吗?你说的 null 是什么意思? - Peyman Mohamadpour
5个回答

34

由于某种原因,我不得不更改Doctrine映射以使其工作:

Asset:
 /**
 * @ORM\ManyToMany(targetEntity="Adaptive\UserBundle\Entity\User", inversedBy="assets")
 * @ORM\JoinTable(name="user_assets")
 */
private $users;

User:
 /**
 * @ORM\ManyToMany(targetEntity="Splash\SiteBundle\Entity\Asset", mappedBy="users")
 */
private $assets;

现在,当我保存资产时,它会保存相关的用户。我不需要将builder->add定义为实体或集合。我只需将其传递为空,并使用映射信息填充实体信息:

AssetType:
->add('users', null, array('expanded' => "true", "multiple" => "true"))

不完全确定为什么需要在“资产”与“用户”之间使用inversedBy和JoinTable信息,但现在似乎可以工作了!

感谢建议!!!


我遇到了类似的问题。建议他人:确保你所有的单数/复数都是正确的,如果你的任何一个实体有多个术语名(例如CoolDude),你可能会受益于知道Doctrine默认假定你的表名只是该名称的小写版本,例如 cooldude。 如果它实际上是cool_dude,我认为你必须明确设置它。你可以在Doctrine文档中看到如何设置。 http://docs.doctrine-project.org/projects/doctrine-orm/en/2.0.x/reference/association-mapping.html#many-to-many-bidirectional - Jason Swett
问题在于当你想要一个类似的表单在反向方向上时,它不起作用。 - Simon Taisne
@slaapwagen 我也遇到了同样的问题。它在反向方面无法工作。你已经找到解决这个问题的方法了吗? - Stephan Vierkant

24

奇怪的是,我在2016年遇到了同样的问题,仍然很难找到解决方案。 我会将其分享给未来的谷歌用户:

问题在于当你保存表单时,Symfony实际上所做的是:

$asset->getUsers()->add($user)

由于你处于关系的反向端,它不会保留你的更改。

你真正需要的是调用以下内容:

$asset->addUser($user)

其中addUser() 在Asset实体上定义如下:

public function addUser(User $user) 
{
    //add to the inverse side
    $this->users->add($user);

    //add on the owning side (only this is persisted)
    $user->addAsset($this); //$user->assets->add($asset);
}
因此,为了使Symfony使用$asset->addUser()方法,您应该在AssetType表单的users字段上设置'by_reference' => false。有关此设置的更多信息,请参见http://symfony.com/doc/current/reference/forms/types/form.html#by-reference。请记住,您还需要以相同的方式定义removeUser()方法(以便它从拥有关系中删除实体)。

1
这应该是被接受的答案。我一直在想,做了一些回溯发布,为什么没有人写这个,最终你带来了你的答案。不错。 - DonCallisto
“Asset” 在这里是拥有方,因此与 Doctrine 文档 冲突。 - Peyman Mohamadpour
@Trix 谢谢,我刚刚再次检查了一下,确实存在用户/资产混淆的问题。我进行了编辑 - 解决方案仍然相同,我只是调整了变量名称以保持一致性。 - Pavel Dubinin

17


0

我以为通过传递null,Doctrine映射会自动识别类型。我有一个类似的设置,使用资产上的类别,它运行得很好。这是我用来填充类别集合的代码:->add('categories',null,array('expanded' =>“true”,“multiple”=>“true”))...此外,我不需要为用户在资产中添加CRUD功能,而只需要能够将当前用户分配给该资产。 - Shawn Northrop
1
实际上,Doctrine的From扩展添加了一个基于元数据的猜测器。如果您已经正确定义了ManyToMany关联,则类型猜测器将配置您的字段为“collection”。所谓正确定义是指,关联的所有者必须是Asset,在您的情况下,这就是您不得不反转映射的原因。 - Florian Klein
1
EntityType+Expanded+Multiple有什么问题? - Peyman Mohamadpour

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