2013-09-30 59 views
0

我有一个可选的外键,我试图设置为null。无论我尝试过什么,在SaveChanges()上,update语句都将外键设置为以前的值而不是null。无法将外键设置为空

简体子类:

public class Child 
{ 
    [Key, Column(Order = 0), ScaffoldColumn(false)] 
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] 
    public int Id { get; set; } 

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

    public virtual Parent Parent { get; set; } 
} 

简化的父类:

public class Parent 
{ 
    [Key, Column(Order = 0), ScaffoldColumn(false)] 
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] 
    public int Id { get; set; } 

    public virtual ICollection<Child> Children { get; set; } 
} 

事情我已经尝试:

  1. 加载子对象,并设置的ParentId空,并设置Parent to null
  2. 加载子对象并设置Pa rentId空并迫使实体状态进行修改
  3. 加载子对象包括父对象,然后在设置这些值为空并迫使实体状态进行修改
  4. 负载父对象,那么孩子对象和。从父对象中移除(子)
  5. 加载Parent对象,然后加载Child对象,然后从Parent中加载.Remove(child),并将Child.ParentId设置为null并将Child.Parent设置为null。

目前我有:

public void RemoveChildFromParent(int childId, int parentId) 
{ 
    Parent parent = _context.Parents.Include(x => x.Children).FirstOrDefault(u => u.Id == parentId); 
    Child child = parent.Children.SingleOrDefault(u => u.Id == childId); 
    parent.Children.Remove(child); 
    child.ParentId = null; 
    child.Parent = null; 
    child.StateOfEntity = StateOfEntity.Modified; 

    _context.ApplyStateChanges(); 
    _context.SaveChanges(); 
} 

在保存更改,SQL UPDATE语句仍然对子对象旧值上的ParentId和我得到这个错误:

System.InvalidOperationException was unhandled by user code 
    HResult=-2146233079 
    Message=The changes to the database were committed successfully, but an error occurred while updating the object context. The ObjectContext might be in an inconsistent state. Inner exception message: A referential integrity constraint violation occurred: The property values that define the referential constraints are not consistent between principal and dependent objects in the relationship. 
    Source=System.Data.Entity 
    StackTrace: 
     at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options) 
     at System.Data.Entity.Internal.InternalContext.SaveChanges() 
     at System.Data.Entity.Internal.LazyInternalContext.SaveChanges() 
     at System.Data.Entity.DbContext.SaveChanges() 
     at Insight.DataLayer.InsightContext.SaveChanges() 
     at Insight.DataLayer.ChildRepository.RemoveChildFromParent(Int32 childId, Int32 parentId) 
     at Insight.BusinessLayer.ParentManager.RemoveChild(Int32 id, Int32 parentId) 
     at Insight.PresentationLayer.Controllers.ParentController.RemoveChild(Int32 id, Int32 parentId) 
     at lambda_method(Closure , ControllerBase , Object[]) 
     at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) 
     at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) 
     at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass37.<>c__DisplayClass39.<BeginInvokeActionMethodWithFilters>b__33() 
     at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49() 
    InnerException: 

此外,不知道它是否重要,但我有LazyLoadingEnabled = false和AutoDetectChangesEnabled = false。

+0

直接运行查询以清空外键时会发生什么? – NotMe

+0

@ChrisLively,对于延迟抱歉。它工作正常,手动运行命令或使用'DbContext.Database.ExecuteSqlCommand()',所以我可能会坚持。它似乎不太适合这种方法,但是在这个小问题上又花了一天的时间。 –

回答

1

我不知道,如果有一个“优雅”地解决这个(也许改变表结构?),但不是花更多的时间在这个小问题,我已经决定使用DbContext.Database.ExecuteSqlCommand()手动读写更新声明。

它在Entity Framework方法中确实感觉像是一种解决方法,但它仅限于此方案,几乎没有时间去做,并且按预期工作。

+1

我放弃了优雅,也做到了这一点。英孚确实有时会让我有些紧张。 – NibblyPig

0

Also, not sure if it matters, but I have ... AutoDetectChangesEnabled = false .

是的,它很重要。您是否默认禁用了自动更改检测(例如,在您的上下文构造函数中)?这很危险,因为如果禁用自动检测 - 即not a trivial thing,则必须知道并了解何时需要手动调用更改检测。通常,只有在确定它不会导致意外结果并确实需要它时(通常出于性能原因,在运行多个实体更新,插入或删除时运行批量操作时),才应设置AutoDetectChangesEnabled = false。我一定会留在true默认

我不知道是什么_context.ApplyStateChanges究竟(似乎是一个自定义的方法),但你的代码的所有其他线路查询后没有调用任何EF方法,直到SaveChanges(和5所描述的方法既不),这是恰恰是其中一种情况(如上面链接的博客文章中所述)禁用自动更改检测的情况是否而不是无需进一步处理。

要解决此问题,您可以尝试在SaveChanges(或可能在ApplyStateChanges之前)之前在您的代码段中调用_context.DetectChanges();。然而,所有的孩子加载父程序是远远昂贵和最简单的解决办法是只装载了孩子,设置FK到null并保存更改 - 这一切启用自动变化检测:

using (var context = new MyContext()) 
{ 
    // as said, the following line should be your default 
    context.Configuration.AutoDetectChangesEnabled = true; 

    var child = context.Children.SingleOrDefault(c => c.Id == childId); 
    if (child != null) 
    { 
     child.ParentId = null; 
     context.SaveChanges(); 
    } 
} 
+0

感谢这篇文章,我将不得不尝试改变它。 '_context.ApplyStateChanges'将我的'StateOfEntity'枚举转换为相应的'EntityState'枚举,因此强制更改被视为Modified。我设置了'AutoDetectChangesEnabled = false',它基于pluralsight上的Entity Framework教程。 –