c# – EF急切加载导航属性问题

我使用EF6与Generic Repository模式.最近我在尝试一次性删除复合实体时遇到了问题.这是一个简化的场景:

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; }
}

要删除具有相关子项的Parent实体,我正在执行以下操作:

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);
    }
}

首先,我通过ID找到父对象,然后将其传递给delete方法,将其状态更改为已删除. context.SaveChanges()最终提交删除.

这很好. find方法只提取了Parent对象而Delete工作,因为我在Children上启用了删除级联.

但是我在Child类中添加了另一个属性的那一刻:

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

public virtual Gender Gender { get; set; }

出于某种原因,EF开始在Parent.Find()方法中提取相关的Children.因此,我收到以下错误:

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.

即使在还原更改(删除Gender属性)后,问题仍然存在.我无法理解这种奇怪的行为!!

我想做的就是删除Parent对象和Children.
围绕它有一些解决方案,但没有一个真正符合我的目的:

>将LazyLoading转为false – this.Configuration.LazyLoadingEnabled = false;这有效,但在我的实际应用程序中,我需要此属性为true.
>首先迭代所有孩子并删除它们,然后删除父项.这似乎充其量只是一种解决方法,而且非常冗长.
>使用Remove()而不是仅仅将EntityState更改为Deleted.我需要跟踪审核更改,以便EntityState帮助那里.

有人可以解释为什么EF加载相关实体即使我不使用它们?

最佳答案 这个问题似乎与背景的生命周期有关.我正在使用工作单元并使用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实体(其结构与Parent类似,具有子项列表).并且可以触发后续用户操作以删除该视图.

我认为这与未被处置的背景有关.也许这与Ninject或UnitOfWork有关,我还没有能够指出. GetById()可能会从上下文缓存或其他东西中拉出整个实体.

但上述解决方法对我有用.只是把它放在那里,以便它可以帮助某人.

点赞