Удаление записи в таблице «многие ко многим»

Я следую главе о безопасности книги Symfony 2.

Вот пример с таблицей USERS и GROUPS. Между USERS и GROUPS существует отношение многие ко многим, которое создает в базе данных таблицу с именем USERGROUPS.

Я хочу удалить запись из USERGROUPS, например:

DELETE from USERGROUPS WHERE user_id = 1 and group_id = 1 

Я не знаю, как это сделать, так как у меня нет файла таблицы USERGROUPS.php.

Например, используя DQL, я хочу иметь возможность сделать это:

$em = $this->getDoctrine()->getEntityManager();
$query = $em->createQuery(
    'DELETE FROM AcmeStoreBundle:UserGroups ug WHERE ug.user_id = :user 
    and ug.group_id = :group'
)->setParameter(array('user' => $userid, 'group' => $groupid));

Надеюсь, вы уловили идею.

Тогда как удалить из этой таблицы?


person Francisco Ochoa    schedule 11.03.2012    source источник


Ответы (2)


Doctrine рассматривает данные как объекты, а не как строки таблицы. Таким образом, в терминах Doctrine есть объекты Group (которые, среди прочего, содержат пользователей группы) и объекты User (каждый из которых имеет свойство, в котором хранятся группы, в которых находится пользователь). Но нет объектов UserGroup. Идея Doctrine (и любой ORM-системы) состоит в том, чтобы позволить разработчику забыть об этих промежуточных таблицах, которые могут понадобиться базе данных, но которые не нужны с точки зрения объектной модели программы.

Итак, что вы хотите сделать, это загрузить соответствующий объект User, удалить группу из ее свойства $groups и сохранить измененный объект User. (Или наоборот, т. е. загрузить соответствующий объект Group и удалить из него пользователя.) DQL может справиться с этим, но я думаю, что проще сделать это без DQL, поскольку оператор DELETE DQL предназначен для удаления целых объектов, а не изменение их свойств.

Пытаться:

$user = $em->find('User', $userId);
$user->removeGroup($groupId); //make sure the removeGroup method is defined in your User model. 
$em->persist($user);
$em->flush(); //only call this after you've made all your data modifications

Примечание: если у вас нет метода removeGroup() в вашей модели пользователя (я думаю, что Symfony может сгенерировать его для вас, но я могу ошибаться), метод может выглядеть следующим образом.

//In User.php, and assuming the User's groups are stored in $this->groups, 
//and $groups is initialized to an empty ArrayCollection in the User class's constructor
//(which Symfony should do by default).

class User
{
    //all your other methods

    public function removeGroup($group)
    {
        //optionally add a check here to see that $group exists before removing it.
        return $this->groups->removeElement($group);
    }
}
person Ethan    schedule 11.03.2012
comment
Итан. Большое спасибо! Это сработало :) Почему symfony не сгенерировал этот метод автоматически? Я считаю, что удаление чего-либо из таблицы «многие ко многим» — очень распространенная задача. - person Francisco Ochoa; 12.03.2012
comment
Да, я всегда задавался вопросом, почему symfony также не генерирует методы удаления (поскольку он генерирует методы addMethods). Рад, что это сработало! - person Ethan; 14.03.2012
comment
Что делать, если в таблице «многие ко многим» имеется 1 000 000 записей, связанных с этим пользователем, и мне нужно удалить только одну? Doctrine загрузит все записи? - person Alexey Kosov; 26.12.2014
comment
@AlexeyKosov Doctrine в этом случае загрузит коллекцию, увлажнив каждый из этих объектов. В этом случае лучше всего использовать DQL и/или QueryBuilder. - person SteveB; 03.07.2017
comment
В этом конкретном случае фан-ошибка Call to method removeElement on non-class type сводила меня с ума, и ваш комментарий and $groups is initialized to an empty ArrayCollection in the User class's constructor помог мне решить ее: мое свойство не было инициализировано в конструкторе. Большое спасибо! - person Vincent de Lagabbe; 07.12.2018
comment
Это удалит только 1 запись, что, если я хочу удалить все записи USERGROUP, связанные с конкретным ПОЛЬЗОВАТЕЛЕМ?? - person Aamir; 31.01.2019

В дополнение к ответу @Ethan одностороннее удаление не работает. Для такой связи manyToMany вам нужно вызвать методы remove из обеих сущностей, например,

$user = $em->findOneById($userId);
$group = $em->findOneById($groupId);

$user->removeGroup($group);
$group->removeUser($user);

$em->persist($user);
$em->flush();
person Sithu    schedule 20.07.2015
comment
Является ли ваше решение эквивалентом удаления из таблицы, где col1=‹val› и col2=‹val›? Делает ли он запрос в объединенной таблице? - person Volatil3; 04.01.2017
comment
Кажется, это так - person Sithu; 05.01.2017