2010-03-31 8 views
33

Uso Entity Framework 4 e ho una relazione padre-figlio con il set "Cascade Delete". Quindi mi aspetterei che quando rimuovo un figlio dal genitore che il bambino viene cancellato quando chiamo SaveChanges().EF 4: Rimuovere l'oggetto figlio dalla raccolta non lo elimina - perché?

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

Invece ottengo un errore:

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.

Quando elimino esplicitamente i bambini (vedi linea commentato), tutto va bene. Cosa mi manca?

+0

Ho avuto lo stesso problema di oggi e credo che questo sia un difetto di progettazione in Entity Framework. La relazione tra le tabelle in SQL Server indica "Elimina orfani" e pertanto dovrebbe funzionare. Funziona così in NHibernate. Fortunatamente puoi farlo funzionare seguendo la risposta di GraemeMiller e le relative domande. –

risposta

28

Non si sta eliminando l'oggetto con l'istruzione remove. Invece si sta tentando di modificare un record e renderlo un orfano (impostando la chiave esterna su null). Il database ha un vincolo non nullo su quella colonna e ti impedisce di farlo.

+2

... quindi se questa è la risposta corretta quale codice è stato utilizzato per eliminare effettivamente la relazione? –

+2

@ Ek0nomik ha detto: repository.DeleteObject (ricetta); –

10

aggiungere context.DeleteObject(recipe) all'interno del ciclo

26

http://weblogs.asp.net/zeeshanhirani/archive/2010/07/23/removing-entity-from-a-related-collection.aspx spiega esattamente cosa ti è successo.


Supponendo di avere un qualcosa di design di classe come questo:

sample class design

Entity Framework genererà le colonne chiave esterna richiesti e aggiungi NOT NULL vincoli per loro, perché tutte le ricette saranno sempre associato esattamente un ControlUnit.

Quindi in fase di esecuzione si dovrà oggetti simili al seguente schema:

object diagram at runtime

Ora il codice entra in gioco e cancellato il rapporto tra la ricetta oggetti e la loro Unità di controllo:

objects with deleted relationships

Cercando di salvare in questo momento, il database non ha un ID ControlUnit da inserire nella chiave esterna NOT NULL colonna. Lo stato dell'oggetto corrente viola il diagramma delle classi sopra riportato e non può essere salvato su un layout di database che è stato generato supponendo che ogni Ricetta sia associata a una ControlUnit. Questo è il motivo per cui il database si rifiuta di salvare le modifiche e si vede l'eccezione.

Questo spiega anche perché funziona quando si rimuove il commento dalla linea di eliminazione dell'ente: l'entità viene rimossa dal database insieme al suo rapporto, in modo vincoli vengono violati, pertanto, non fa eccezione.

"Ma io impostare ON DELETE CASCADE sul rapporto ..."

Sì, ma che viene attivato solo sulla eliminazione dell'oggetto, non sulla cancellazione del rapporto.Con ON DELETE CASCADE set, questo dovrebbe funzionare:

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

Se si desidera attivare la cancellazione dei soggetti ricetta su cancellazione del loro rapporto con Unità di controllo, il vostro rapporto non dovrebbe essere una semplice associazione, ma piuttosto una composizione:

updated class diagram with composition

EF non supporta questo in modo nativo, ma è possibile emulare il comportamento utilizzando le relazioni di identificazione. Una volta che un'entità si trova in una relazione identificativa con un'entità padre e tale relazione viene rimossa, anche l'entità viene rimossa. Sembra che questa fosse la tua intenzione dall'inizio. Per ulteriori informazioni sull'identificazione della relazione, vedere Implementing identifying relationships with EF4 in cui ho implementato le relazioni di identificazione con EF4 e ho collegato a più materiale di lettura.

3

Io uso questa estensione al fine di non aggiungere un metodo in DAL solo per eliminare un soggetto (codice preso 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); 
} 

Così ho quindi eliminare un'entità come Order.Products.Delete(prod).

I vincoli per utilizzare l'estensione sono:
- L'entità deve avere relazioni;
- L'entità deve essere collegata a ObjectContext.

6

Se si rende identificabile la relazione tra figlio e padre, è possibile rimuovere le entità figlio dalla raccolta. È necessario rendere la chiave del bambino una chiave composta contenente la chiave id principale del genitore. In questo modo EF sa che è necessario rimuovere il bambino.

La relazione di identificazione dice fondamentalmente se il genitore non esiste, quindi il bambino non ha significato. Ciò significa che EF sa che è sicuro eliminare il bambino quando la relazione viene rimossa.

Vai a questa domanda Identifying Relationship and inserting child entities causes "Cannot insert explicit value for identity column in table" e questo Is it possible to remove child from collection and resolve issues on SaveChanges?

+0

Vedere anche http://stackoverflow.com/questions/3710191/implementing-identifying-relationships-with-ef4 dove ho riscontrato questo problema e ho spiegato come creare relazioni identificative. C'è anche un link a un post sul blog che lo spiega in dettaglio. – Chris

Problemi correlati