web-dev-qa-db-fra.com

EF 4: Suppression de l'objet enfant de la collection ne le supprime pas - pourquoi?

J'utilise entité Framework 4 et j'ai la relation parent - enfant avec "Cascade Supprimer" Set. Je m'attendrais donc lorsque je retire un enfant du parent que l'enfant est supprimé lorsque j'appelle Savechanges ().

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

Au lieu de cela, j'ai une erreur:

System.invalidoperationExceptionException survenue Message = L'opération a échoué: la relation n'a pas pu être modifiée car une ou plusieurs des propriétés de clé étrangère ne sont pas nullables. Lorsqu'une modification est faite à une relation, la propriété Key de l'étranger associée est définie sur une valeur null. Si la clé étrangère ne prend pas en charge les valeurs NULL, une nouvelle relation doit être définie, la propriété de clé étrangère doit être attribuée à une autre valeur non nulle ou l'objet non liée doit être supprimé.

Lorsque j'ai explicitement supprimer les enfants (voir ligne commentée), tout va bien. Qu'est-ce que je rate?

33
H. Kocher

Vous ne supprimez pas l'objet avec la déclaration Supprimer. Au lieu de cela, vous essayez de modifier un enregistrement et de le faire un orphelin (en définissant la clé étrangère à NULL). La base de données a une contrainte non nulle sur cette colonne et vous empêche de le faire.

28
Amy B

http://weblogs.asp.net/zeeshanhirani/archive/2010/07/23/reMoving-entity-de-a-related-collection.aspx Explique exactement ce qui vous est arrivé.


En supposant que vous ayez une conception de classe quelque chose comme ceci:

sample class design

L'entité framework générera les colonnes de clés étrangères requises et ajoutera NOT NULL contraintes d'eux parce que toutes les recettes seront toujours associées à exactement un contrôle.

Donc, au moment de l'exécution, vous aurez des objets similaires à la mise en page suivante:

object diagram at runtime

Maintenant, votre code entre en jeu et supprimé la relation entre les objets de recette et leur contrôunit:

objects with deleted relationships

Essayer d'économiser en ce moment, la base de données n'a pas d'ID de Controlunit pour mettre dans la clé étrangère NOT NULL colonne. L'état de l'objet actuel viole le diagramme de classe ci-dessus et ne peut pas être enregistré dans une disposition de la base de données générée sous l'hypothèse que chaque recette est associée à une unité de contrôle. C'est pourquoi la base de données refuse de sauvegarder les modifications et de voir l'exception.

Cela explique également pourquoi cela fonctionne lorsque vous déconnectez la ligne Suppression de la ligne Suppression de l'entité: L'entité est supprimée de la base de données avec sa relation, aucune contrainte n'est violée, donc aucune exception.

"mais j'ai défini ON DELETE CASCADE sur la relation ... "

Oui, mais cela n'est déclenché que sur la suppression de l'objet, pas sur la suppression de la relation. Avec ON DELETE CASCADE Ensemble, cela devrait fonctionner:

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

Si vous souhaitez déclencher la suppression des entités de recette sur la suppression de leur relation avec ControlUnit, votre relation ne doit pas être une simple association, mais plutôt une composition:

updated class diagram with composition

EF ne supporte pas cela de manière native, mais vous pouvez imiter le comportement en utilisant des relations d'identification. Une fois qu'une entité est dans une relation d'identification d'une entité parentale et que la relation est supprimée, l'entité est également supprimée. Il semble que c'était votre intention de commencer. Pour plus d'informations sur l'identification de la relation, voir Mise en œuvre des relations d'identification avec EF4 où j'ai implémenté l'identification des relations avec EF4 et lié à plus de matériel de lecture.

26
Chris

ajouter context.DeleteObject(recipe) À l'intérieur de la boucle

11
vittore

Si vous faites la relation entre enfant et parent, identifiez-vous, vous pouvez supprimer les entités d'enfants de la collection. Vous devez faire la clé de l'enfant une clé composite contenant la clé d'identité principale du parent. De cette façon, EF sait qu'il doit retirer l'enfant.

L'identification de la relation dit fondamentalement si le parent n'existe pas, alors l'enfant n'a aucune signification. Cela signifie que EF sait qu'il est prudent de supprimer l'enfant lorsque la relation est supprimée.

Voir cette question identification de la relation et insertion d'entités enfants Les causes "ne peuvent pas insérer de valeur explicite pour la colonne d'identité dans le tableau" et celui-ci est-il possible de supprimer l'enfant de la collecte et de résoudre les problèmes sur SAVECHANGES?

6
GraemeMiller

J'utilise cette extension afin de ne pas ajouter une méthode de DAL pour supprimer une entité (code prélevé sur 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);
}

Donc, je supprimai ensuite une entité comme Order.Products.Delete(prod).

Les contraintes d'utiliser l'extension sont les suivantes:
[.____] - L'entité doit avoir des relations;
[.____] - L'entité doit être attachée à ObjectContext.

3
net_prog