我使用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()可能会从上下文缓存或其他东西中拉出整个实体.
但上述解决方法对我有用.只是把它放在那里,以便它可以帮助某人.