2013-09-30 3 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 нуль и установить От родителя до нуля
  2. Загрузите объект Child и установите Pa rentId null и принудительно изменить состояние объекта
  3. Загрузите объект Child, включая родительский объект, затем установите значения в значение null и принудительно измените состояние объекта.
  4. Загрузите родительский объект, а затем объект Child и. Удалить (дочерний элемент) из родительского объекта
  5. Загрузите родительский объект, затем объект Child и .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(); 
} 

на Save Changes, Заявление 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

Я отказался от элегантности и сделал это тоже. Иногда EF действительно нервничает. – 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 описанных процедур) точно в одной из ситуаций (как описано в связанном сообщении в блоге выше), где отключается автоматическое обнаружение изменений не работать без дополнительного ухода.

Чтобы устранить проблему, вы можете попробовать позвонить _context.DetectChanges(); в свой фрагмент кода до SaveChanges (или, может быть, до ApplyStateChanges). Однако процедура загрузки родителя со всеми детьми далеко дорогим и самым простым решением было бы просто загружая ребенка, установите 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', заставляя изменения восприниматься как Модифицированные. Я устанавливаю 'AutoDetectChangesEnabled = false' на основе учебника Entity Framework по множественности. –

Смежные вопросы