2010-03-31 8 views
33

Używam Entity Framework 4 i mam relacji parent - child z zestawem "Cascade Delete". Tak więc oczekiwałbym, gdy usunę dziecko z rodzica, że ​​dziecko zostanie usunięte, gdy zadzwonię SaveChanges().EF 4: Usunięcie obiektu podrzędnego z kolekcji nie powoduje jego usunięcia - dlaczego?

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

Zamiast tego pojawia się błąd:

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.

Kiedy jawnie usunąć dzieci (patrz skomentowany linia), wszystko jest w porządku. czego mi brakuje?

+0

miałem dzisiaj ten sam problem i wierzę, że jest to wada projektu w Entity Framework. Relacja między tabelami w SQL Server brzmi "Cascade delete sieroty" i dlatego powinna działać. Działa tak w NHibernate. Na szczęście można go uruchomić po odpowiedzi GraemeMiller i powiązanych z nimi pytaniach. –

Odpowiedz

28

Nie usuwasz obiektu za pomocą polecenia remove. Zamiast tego próbujesz zmienić rekord i uczynić go sierotą (ustawiając klucz obcy na wartość null). Baza danych ma nie-puste ograniczenie w tej kolumnie i uniemożliwia to.

+2

... więc jeśli jest to poprawna odpowiedź, jaki kod został użyty do usunięcia powiązania? –

+2

@ Ek0nomik powiedział: reository.DeleteObject (przepis); –

10

dodać context.DeleteObject(recipe) wewnątrz pętli

26

http://weblogs.asp.net/zeeshanhirani/archive/2010/07/23/removing-entity-from-a-related-collection.aspx wyjaśnia dokładnie, co się stało.


Zakładając, że klasa zaprojektować coś takiego:

sample class design

Entity Framework wygeneruje wymaganych kolumn klucza obcego i dodać NOT NULL ograniczenia do nich, ponieważ wszystkie przepisy będą zawsze wiąże się z dokładnie jeden ControlUnit.

Więc przy starcie będziesz mieć obiekty podobne do następującym układzie:

object diagram at runtime

Teraz kod wchodzi w grę i usunięte relacja między Receptura obiektów i ich ControlUnit:

objects with deleted relationships

Próbując zapisać w tej chwili, baza danych nie ma identyfikatora ControlUnit, który można umieścić w kolumnie klucza obcego NOT NULL. Obecny stan obiektu narusza powyższy diagram klasy i nie można go zapisać w układzie bazy danych, który został wygenerowany przy założeniu, że każdy przepis jest powiązany z jedną jednostką ControlUnit. Dlatego baza danych odmawia zapisania zmian i widzisz wyjątek.

Wyjaśnia to również, dlaczego działa po odkomentowaniu linii usuwającej encję: encja jest usuwana z bazy danych wraz z relacją, więc nie są naruszane ograniczenia, a zatem nie ma wyjątków.

„Ale ja ustawić ON DELETE CASCADE na relacji ...”

Tak, ale to jest wyzwalany tylko na usunięcie obiektu, a nie na usunięcie relacji.Z ON DELETE CASCADE zestawie, to powinno działać:

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

Jeśli chcesz wywołać usunięcie podmiotów receptur na usunięcie ich relacji z ControlUnit, twój związek nie powinien być prosty stowarzyszenie ale raczej kompozycja:

updated class diagram with composition

EF nie obsługuje tego natywnie, ale można emulować zachowanie za pomocą relacji identyfikujących. Gdy jednostka znajduje się w relacji identyfikującej z jednostką nadrzędną, a relacja ta jest usuwana, jednostka jest również usuwana. Wygląda na to, że to była twoja intencja od samego początku. Aby uzyskać więcej informacji na temat identyfikacji relacji, zobacz Implementing identifying relationships with EF4 gdzie zaimplementowałem relacje identyfikujące z EF4 i powiązałem je z większą ilością materiałów do czytania.

3

Używam tego rozszerzenia, aby nie dodać metodę w DAL prostu usunąć jednostkę (kod zaczerpnięty z 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); 
} 

Więc następnie usunąć podmiot jak Order.Products.Delete(prod).

Ograniczenia w używaniu rozszerzenia to:
- Podmiot musi mieć relacje;
- Podmiot musi być dołączony do ObjectContext.

6

Jeśli sprawisz, że relacje między dzieckiem i rodzicem będą identyczne, możesz usunąć elementy podrzędne z kolekcji. Musisz uczynić klucz potomny kluczem złożonym zawierającym główny klucz id rodzica. W ten sposób EF wie, że musi usunąć dziecko.

Zidentyfikowanie związku zasadniczo mówi, że jeśli rodzic nie istnieje, dziecko nie ma znaczenia. Oznacza to, że EF wie, że bezpieczne jest usunięcie dziecka po usunięciu związku.

Zobacz to pytanie Identifying Relationship and inserting child entities causes "Cannot insert explicit value for identity column in table" a ten Is it possible to remove child from collection and resolve issues on SaveChanges?

+0

Zobacz także http://stackoverflow.com/questions/3710191/implementing-identifying-relationships-with-ef4, gdzie napotkałem ten problem i wyjaśniono, jak tworzyć relacje identyfikujące. Istnieje również link do postu na blogu, który wyjaśnia to szczegółowo. – Chris

Powiązane problemy