Удаление в коде EF сначала приводит к тому, что навигационные свойства устанавливаются в нулевое и пустое - PullRequest
4 голосов
/ 21 июля 2011

Я заметил кое-что интересное, когда выполнял удаление сначала с использованием кода EF.Я использую следующую модель домена:

public class User
{
    public virtual long Id { get; set; }
    public virtual string Name { get; set; }
    public virtual ICollection<Playlist> Playlists { get; set; }
}

public class Playlist
{
    public virtual long Id { get; set; }
    public virtual string Title { get; set; }
    public virtual User User { get; set; }
    public virtual ICollection<Track> Tracks { get; set; }
}

public class Track
{
    public virtual long Id { get; set; }
    public virtual string Title { get; set; }
    public virtual Playlist Playlist { get; set; }
}

Модель настроена с использованием:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<User>().HasMany(x => x.Playlists).WithRequired(x => x.User).Map(x => x.MapKey("UserId"));
    modelBuilder.Entity<Playlist>().HasMany(x => x.Tracks).WithRequired(x => x.Playlist).Map(x => x.MapKey("PlaylistId"));
}

Я использую общий репозиторий:

public virtual void Delete(T entity)
{
    Database.Set<T>().Remove(entity);
}

У меня также естьЭто выглядит следующим образом:

public class PlaylistDTO
{
    public PlaylistDTO(Playlist playlist)
    {
        Id = playlist.Id;
        Title = playlist.Title;
        User = playlist.User.Name;
    }
}

В одном из моих сервисов я пытаюсь сделать следующее:

public PlaylistDTO Delete(long id)
{
    Playlist playlist = playlistRepository.GetById(id);
    playlistRepository.Delete(playlist);
    unitOfWork.Commit();

    return PlaylistDTO(playlist);
}

Этот код не выполняется.Когда я прошел через отладчик, я заметил кое-что интересное.В тот момент, когда я вызываю playlistRepository. Удалите навигационные свойства (User и Tracks), которые будут установлены в null и empty соответственно.Однако плейлист остается в памяти.Поэтому, когда я передаю плейлист DTO, код не работает, когда он пытается получить доступ к playlist.User.Name.Я хотел передать эти данные клиенту для отображения подтверждения.

Правильно ли это поведение?Это по замыслу?

1 Ответ

7 голосов
/ 22 июля 2011

Так работает EF.Проблема в том, что ваш Playlist формирует граф сущностей с другими отношениями, а EF использует очень простое правило для отслеживания графов сущностей: все сущности в графе должны отслеживаться - не может быть ссылки на сущность, которая не отслеживается.Я не даю вам ссылку на описание этого правила, это просто мое наблюдение, но я не нашел ни одного исключения из этого правила.

Редактировать: Обновленная версия - я только что проверил внутреннюю реализациюи отношения действительно обнуляются во время вызова Delete

Итак, что произошло в вашем коде.

  • Вы отметили Playlist как удаленное
  • EF передает операцию удаления менеджеру состояния, который выполняет исправление - он обнуляет все отношения
  • Вы сохранили изменения в базе данных
  • Поскольку нет каскадных удалений из Playlist, все связанные объекты остаются не восстановленными
  • После того, как вы сохранили изменения, EF принял их внутренне и установил трекер изменений на текущийсостояние
  • Поскольку текущее состояние Playlist не существует (удалено в базе данных), оно было отсоединено от контекста
  • При откреплении поврежден граф сущностей, а EF исправил его, изменивсвойства навигации на обоих концах

Код, отвечающий за обнуление от System.Data.Objects.EntityEntry.Delete(doFixup) (doFixup - true) - класс является внутренним:

if (doFixup && (base.State != EntityState.Deleted))
{
    this.RelationshipManager.NullAllFKsInDependentsForWhichThisIsThePrincipal();
    this.NullAllForeignKeys();
    this.FixupRelationships();
}

В вашемВ этом сценарии должен быть простой обходной путь - создайте DTO перед удалением сущности.

...