EF удалить отношения "многие ко многим"

Представьте себе эту модель базы данных:

public class User
{
  public int Id { get; set; }
  public string Username { get; set; }
  public string Firstname { get; set; }
  public ICollection<Role> Roles { get; set; }
}

public class Role
{
  public int Id { get; set; }
  public string RoleType { get; set; }
  public ICollection<User> Users { get; set; }
}

Существует промежуточная таблица, которая выглядит следующим образом (не представлена ​​в виде POCO):

UserRole

Затем я решил удалить роль, а это значит, что все отношения этой роли в промежуточной таблице также должны быть удалены.

Независимо от того, что я пытаюсь, я получаю либо это сообщение об ошибке:

Инструкция DELETE конфликтует с ограничением REFERENCE "FK_UserRole_Role". Конфликт произошел в базе данных "dbname", таблице "dbo.UserRole", столбце "RoleId".

Или это сообщение об ошибке:

Объект нельзя удалить, так как он не найден в ObjectStateManager.

Первое сообщение об ошибке исходит от этой попытки:

_dataContext.Entry(role).State = EntityState.Deleted;
_dataContext.SaveChanges();

Это отвечает за второе сообщение об ошибке:

_dataContext.Circuit.Remove(role);
_dataContext.SaveChanges();

Я сделал еще несколько попыток, но я их не помню, так как пытался заставить это работать с сегодняшнего утра (GMT +2).

Может ли кто-нибудь указать мне правильное направление?


person Yustme    schedule 09.07.2013    source источник


Ответы (1)


Вы можете заставить второе исключение исчезнуть, сначала присоединив role к контексту, прежде чем вызывать Remove:

_dataContext.Roles.Attach(role);
_dataContext.Roles.Remove(role);
_dataContext.SaveChanges();

Но тогда вы, скорее всего, получите первое исключение и для этого кода, потому что реальная проблема заключается в том, что вы, по-видимому, не включили каскадное удаление в базе данных для двух отношений из таблицы UserRoles в таблицу Users и таблицу Roles соответственно.

Вы можете установить правило удаления для обоих отношений на «Каскад» в SQL Server Management Studio как показано здесь, например. После этого удаление роли также должно привести к удалению записей в таблице ссылок UserRoles.

Изменить

Когда вы загружаете связанных пользователей, вы также можете успешно удалить роль без включения каскадного удаления:

var role = _dataContext.Roles.Include(r => r.Users)
    .Single(r => r.Id == someRoleId);

_dataContext.Roles.Remove(role);
// _dataContext.Entry(role).State = EntityState.Deleted; will work as well
_dataContext.SaveChanges();

Разница в том, что когда связанные пользователи присоединяются к контексту вместе с ролью, EF будет отправлять отдельный оператор DELETE для каждой строки в таблице ссылок UserRoles, а затем оператор DELETE для роли, чтобы он работал без нарушения ограничения FK.

person Slauma    schedule 09.07.2013
comment
Привет, самое смешное, что именно этот сценарий используется в двух других объектах, где каскадирование не включено. Но он удаляет сущность и записи в таблице ссылок. Я просто не могу понять, насколько этот сценарий отличается от другого, где он работает как шарм. - person Yustme; 09.07.2013
comment
@Yustme: Возможно, разница в том, что вы загрузили/присоединили связанные объекты в другом отношении. Тогда удаление работает иначе, и оно действительно будет работать без каскадного удаления. См. мое редактирование выше. - person Slauma; 09.07.2013
comment
Мне тоже попался такой образец. Но когда я использую «Включить», он ожидает строку. Нельзя использовать лямбда-выражения. Есть идеи, почему? - person Yustme; 09.07.2013
comment
@Yustme: вы должны добавить using System.Data.Entity; в свой файл кода. - person Slauma; 09.07.2013