4

Я использую EF6 с шаблоном Generic Repository. Недавно у меня возникла проблема с попыткой удалить составной объект за один раз. Вот упрощенный вариант:EF с нетерпением Загрузка свойств навигационных свойств

public class Parent 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public virtual ICollection<Child> Children { get; set; } 
} 
public class Child 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 

    [ForeignKey("Parent")] 
    public int ParentId { get; set; } 

    public virtual Parent Parent { get; set; } 
} 

Для удаления родительского объекта со связанными детьми я делаю что-то вроде этого:

public virtual T GetById(int id) 
{ 
    return this.DBSet.Find(id); 
} 
public virtual void Delete(T entity) 
{ 
    DbEntityEntry entry = this.Context.Entry(entity); 

    if (entry.State != EntityState.Deleted) 
    { 
     entry.State = EntityState.Deleted; 
    } 
    else 
    { 
     this.DBSet.Attach(entity); 
     this.DBSet.Remove(entity); 
    } 
} 

Сначала я найти родительский объект по идентификатору, а затем передать его удаление метод изменения состояния для удаления. Контекст .SaveChanges(), наконец, завершает удаление.

Это сработало отлично. Метод find только остановил объект «Родитель» и «Удалить», так как у меня есть каскад при удалении, который включен в «Дети».

Но в тот момент я добавил еще одно свойство в классе детей:

[ForeignKey("Gender")] 
public int GenderId { get; set; } 

public virtual Gender Gender { get; set; } 

По какой-то причине EF потащил связанных детей по методу Parent.Find(). Из-за этого я получаю следующее сообщение об ошибке:

The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.

Даже после возвращения изменений (удаления собственности Гендерной) проблема все еще существует. Я не могу понять это странное поведение !!

Все, что я хочу сделать, это удалить родительский объект вместе с детьми. Есть несколько решений вокруг него, но никто на самом деле не служит своей цели:

  1. Turn LazyLoading ложь - this.Configuration.LazyLoadingEnabled = ложь; Это работает, но в моем реальном приложении мне нужно, чтобы это свойство было истинным.
  2. Сначала идите всех детей и удалите их, а затем удалите родителя. Это, в лучшем случае, обходное решение и очень многословно.
  3. Используйте Remove() вместо того, чтобы просто изменять EntityState на Deleted. Мне нужно отслеживать изменения для аудита, поэтому там помогает EntityState.

Может кто-нибудь объяснить, почему EF загружает связанные объекты, даже если я их не использую?

+0

Когда вы вернулись, вы также вернули БД? Вероятно, ваша проблема связана с БД. – Sefe

+0

Да, я сделал. Я бросил БД и воссоздал ее. –

+0

Я сомневаюсь, что это связано с БД, потому что я могу удалить родительский объект с запросом sql и каскадом при удаленных работах для детей. –

ответ

2

Кажется, что проблема была связана с жизненным циклом контекста. Я использую Unit Of Work и внедряю его в свои сервисные слои, используя ninject.

kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope(); 

Класс Unitowork реализует IDisposable.

public bool DeleteView(int viewId) 
    { 
     // This is a workaround. It seems ninject is not disposing the context. 
     // Because of that all the info (navigation properties) of a newly created view is presisted in the context. 
     // Hence you get a referential key error when you try to delete a composite object. 
     using (var context = new ApplicationDbContext()) 
     { 
      var repo = new GenericRepository<CustomView>(context); 
      var view = repo.GetById(viewId); 
      repo.Delete(view); 
      context.SaveChanges(); 
     } 
     //var model = _unitOfWork.CustomViews.GetById(viewId); 
     //_unitOfWork.CustomViews.Delete(model); 
     //_unitOfWork.Save(); 

     return true; 
    } 

Прокомментированный код содержит ошибки и ошибки, в то время как без комментариев (с использованием блока) работает. Метод контроллера перед этим вызовом загружает объект CustomView (который похож на структуру с родителем со списком дочерних элементов). И последующее действие пользователя может быть инициировано для удаления этого представления.

Я считаю, что это имеет какое-то отношение к тому, что контекст не используется. Может быть, это имеет какое-то отношение к Ninject или UnitOfWork, я еще не смог сказать. GetById() может вытащить весь объект из кеша контекста или что-то еще.

Но вышеупомянутое обходное решение работает для меня. Просто поместите его туда, чтобы он мог помочь кому-то.

+0

Использование Autofac - гораздо более зрелый и простой в понимании решение для жизни, областей, ресурсов и единиц работы (по запросу). –

+0

Другими словами, вся почта неверна и не имеет ничего общего с EF, но шаблоны, инъекции и т. Д. Я думаю, что как только победа истекает, вопрос должен быть удален, потому что это просто вводит в заблуждение, и я не вижу, как это может помочь кто-то. –