2010-03-31 5 views
33

Я использую Entity Framework 4, и у меня есть отношение parent-child с установкой «Cascade Delete». Так что я ожидал бы, когда я удалю дочерний элемент из родителя, когда ребенок будет удален, когда я вызову SaveChanges().EF 4: Удаление дочернего объекта из коллекции не удаляет его - почему?

 cuRepository.Attach(_controlUnit); 
     foreach (var recipe in recipes) { 
      _controlUnit.Recipes.Remove(recipe); 
      //repository.DeleteObject(recipe); 
     } 

Вместо этого я получаю сообщение об ошибке:

System.InvalidOperationException occurred Message=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.

Когда я явно удалить ребенок (см комментируемой строки), все это хорошо. Что мне не хватает?

+0

Я была такая же проблема сегодня, и я считаю, что это конструктивный недостаток в Entity Framework. Взаимосвязь между таблицами в SQL Server означает «Cascade delete сирот» и поэтому должна работать. Это работает в NHibernate. К счастью, вы можете заставить его работать после ответа GraemeMiller и связанных с ним вопросов. –

ответ

28

Вы не удаляете объект с помощью инструкции remove. Вместо этого вы пытаетесь изменить запись и сделать ее сиротой (установив для внешнего ключа значение null). База данных имеет ненулевое ограничение в этом столбце и не позволяет вам этого делать.

+2

... так что если это правильный ответ, какой код использовался для фактического удаления отношений? –

+2

@ Ek0nomik он сказал: repository.DeleteObject (рецепт); –

10

добавить context.DeleteObject(recipe) внутри цикла

26

http://weblogs.asp.net/zeeshanhirani/archive/2010/07/23/removing-entity-from-a-related-collection.aspx объясняет то, что случилось с вами.


Если у вас есть дизайн класс что-то вроде этого:

sample class design

Entity Framework будет генерировать необходимые столбцы внешнего ключа и добавить NOT NULL ограничения для них, потому что все рецепты всегда будут связаны с точно один ControlUnit.

Так во время выполнения вы будете иметь объекты, подобные следующий макет:

object diagram at runtime

Теперь ваш код входит в игру и удалили связь между рецептом объектами и их устройство управления:

objects with deleted relationships

Пытается сэкономить на данный момент, база данных не имеет идентификатора ControlUnit для ввода внешнего ключа NOT NULL. Текущее состояние объекта нарушает приведенную выше диаграмму классов и не может быть сохранена в макете базы данных, которая была сгенерирована в предположении, что каждый рецепт связан с одним элементом ControlUnit. Вот почему база данных отказывается сохранять изменения, и вы видите исключение.

Это также объясняет, почему это работает, когда вы разорёте строку, удаляющую объект: Сущность удаляется из базы данных вместе с ее отношением, поэтому никаких ограничений не нарушаются, поэтому исключение не существует.

«Но я поставил ON DELETE CASCADE на отношения ...»

Да, но это срабатывает только при удалении объекта, а не на удаление отношений.С ON DELETE CASCADE набором, это должно работать:

controlUnitRepository.DeleteObject(_controlUnit); 
// deletes the ControlUnit and all associated Recipe entities 

Если вы хотите, чтобы вызвать удаление рецепта лиц на удалении их отношений с устройством управления, ваши отношения не должно быть простое объединением, а композиция:

updated class diagram with composition

EF не поддерживает это изначально, но вы можете эмулировать поведение, используя идентифицирующие отношения. Когда объект находится в идентифицирующей связи с родительским объектом и эта связь удаляется, объект также удаляется. Кажется, это было ваше намерение с самого начала. Дополнительную информацию об идентификации отношений см. В разделе Implementing identifying relationships with EF4, где я реализовал идентификацию отношений с EF4 и связал их с большим количеством материалов для чтения.

3

Я использую это расширение для того, чтобы не добавить метод в DAL просто удалить объект (код, взятый из http://blogs.msdn.com/b/alexj/archive/2009/06/08/tip-24-how-to-get-the-objectcontext-from-an-entity.aspx):

public static void Delete<T>(this EntityCollection<T> collection, T entityToDelete) where T : EntityObject, IEntityWithRelationships 
{ 
    RelationshipManager relationshipManager = entityToDelete.RelationshipManager; 

    IRelatedEnd relatedEnd = relationshipManager.GetAllRelatedEnds().FirstOrDefault(); 
    if (relatedEnd == null) 
    { 
     throw new Exception("No relationships found for the entity to delete. Entity must have at least one relationship."); 
    } 

    var query = relatedEnd.CreateSourceQuery() as ObjectQuery; 
    if (query == null) 
    { 
     throw new Exception("The entity to delete is detached. Entity must be attached to an ObjectContext."); 
    } 

    query.Context.DeleteObject(entityToDelete); 
    collection.Remove(entityToDelete); 
} 

Я тогда удалить объект как Order.Products.Delete(prod).

Ограничения на использование расширения:
- Сущность должна иметь отношения;
- Объект должен быть привязан к ObjectContext.

6

Если вы установили связь между дочерним и родительским идентификационными данными, вы можете удалить дочерние объекты из коллекции. Вам нужно сделать ключ ребенка составным ключом, содержащим основной ключ ключа родителя. Таким образом, EF знает, что нужно удалить ребенка.

Идентификация отношения в основном говорит о том, что родитель не существует, тогда у ребенка нет значения. Это означает, что EF знает, что безопасно удалять ребенка при удалении отношения.

Смотрите этот вопрос Identifying Relationship and inserting child entities causes "Cannot insert explicit value for identity column in table" и это один Is it possible to remove child from collection and resolve issues on SaveChanges?

+0

См. Также http://stackoverflow.com/questions/3710191/implementing-identifying-relationships-with-ef4, где я столкнулся с этой проблемой и объяснил, как создавать идентифицирующие отношения. Существует также ссылка на сообщение в блоге, объясняющее это подробно. – Chris