2013-09-30 62 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教程。 –