2011-12-02 12 views
16

Oto scenariusz:Najpierw kod EF: Jak usunąć wiersz z kolekcji jednostki, gdy podążasz za DDD?

DDD stwierdza, że ​​używasz repozytorium, aby uzyskać zagregowany katalog główny, a następnie użyć go do dodania/usunięcia do wszystkich posiadanych kolekcji.

Dodawanie jest proste, wystarczy zadzwonić pod numer .Add(Item item) na Collection, do którego chcesz dodać. Nowy wiersz zostanie dodany do bazy danych po zapisaniu. Jednak usuwanie jest inne - wywołanie .Remove(Item item) nie usuwa pozycji z bazy danych, po prostu usuwa klucz obcy. Tak więc, chociaż tak, to technicznie nie jest już częścią kolekcji, wciąż jest w bazie danych.

Jedynym rozwiązaniem jest usunięcie go przy użyciu kontekstu danych. Ale zgodnie z DDD obiekt domeny nie powinien być świadomy kontekstu danych, dlatego usuwanie będzie musiało być wykonane poza domeną.

Jaki jest właściwy sposób postępowania w tej sprawie? Lub Czy pozostawiają bazę danych pełną sierot akceptowalną (być może wykonując rutynę, aby je usunąć)?

Odpowiedz

10

Rozwiązałem ten problem w aplikacji, nad którą obecnie pracuję, używając domain events; koncepcja DDD Eric Evans said powinna być w jego książce.

Podczas gdy obiekty domeny nie mogą wiedzieć o kontekście obiektu, IDomainEventHandler jest - dlatego mam DomainObjectDeletionHandler, który usuwa "usunięte" obiekty z kontekstu obiektu, zanim sterowanie powróci do mojej warstwy aplikacji, a zmiany są zapisane.

Aby uzyskać więcej informacji, napisałem a blog o mojej implementacji zdarzeń domeny i o tym, jak zbliżyłem się do wszystkiego.

nadzieję, że pomoże :)

Edit

Na przykład, jeśli masz klasę Order który ma OrderItems kolekcję typu OrderItem:

public class Order 
{ 
    // Other stuff 

    public void RemoveOrderItem(int orderItemId) 
    { 
     var orderItemToRemove = OrderItems.First(oi => oi.Id == orderItemId) 

     OrderItems.Remove(orderItemToRemove); 

     DomainEvents.Raise(new OrderItemRemoved(orderItemToRemove)); 
    } 
} 
+0

Fantastyczny, na miejscu na – highace

+0

Kiedy dokładnie wzniesiesz wydarzenie usunięcia? –

+0

Z metody w obiekcie domeny powodującej usunięcie - zaktualizowałem odpowiedź. –

2

ja nie wiem, czy jest to zgodne z projektem, ale jeśli obiekt szczegółów zawiera klucz złożony zawierający kolumny klucza obiektu głównego, zostanie on automatycznie usunięty, jeśli usuniesz go z obiektu r kolekcja obiektu. Jeśli masz obiekt zamówienia z kluczem OrderID i właściwością nawigacji Linia zamówienia ICollection, podaj OrderLine klucz złożony zawierający OrderID i OrderLineID.

Ale ponieważ nie wiem, czy mogę na tym polegać, rozwiązaniem, które sam wykorzystałem, jest umożliwienie EF radzenia sobie z nim w sposób, w jaki to robi, i naprawianie "detached" (nie w kategoriach EF) obiektów szczegółowych na wywołanie SaveChanges(), wyliczanie wszystkich zmodyfikowanych encji i zmiana stanu na odpowiednio usunięte.

+1

Pod względem EF nazywa się to [relacją identyfikującą] (http://stackoverflow.com/questions/4922228/entity-framework-4-delete-object-from-entity-collection/4925040#4925040). –

4

Podczas usuwania elementu podrzędnego z kolekcji EF pozostawi go jako osierocone, usuwając tylko klucz obcy.

Jeśli nie chcesz jawnie usunąć go za pomocą DbContext, możesz użyć tego, co nazywa się "Identifying Relationship" (http://msdn.microsoft.com/en-us/library/ee373856.aspx u dołu).

Sztuką jest ustawienie złożonego klucza podstawowego na elemencie podrzędnym, w tym klucza podstawowego rodzica.

Gdy to zrobisz, usuwając encję z kolekcji rodzica, zostanie ona również usunięta z tabeli.

+0

Ta odpowiedź jest zaniżona. Ja też początkowo byłem zaniepokojony zachowaniem EF na "osierocenie" usuniętych encji (lub w przypadku ograniczeń klucza obcego, jego niemożnością w ogóle), ale konfiguracja klucza złożonego, jak wspomniano, rzeczywiście spowodowała fizyczne usunięcie tych obiektów z bazy danych kiedy je usuniesz. Uwielbiam niektóre z innych sugestii, takich jak używanie zdarzeń domeny, ale wydaje się prostszą poprawką, aby po prostu zmienić klucz. – Funka

0

Dlaczego nie korzystać z dwóch repozytoriów?

var parent = ParentRepo.Get(parentId); 
parent.Children.Remove(childId); // remove it from the property Collection 
ChildRepo.Delete(childId); // delete it from the database 
ParentRepo.Commit(); // calls underlying context.SaveChanges() 

Zakładając jesteś dzielenie konteksty przez IOC/DI, nazywając popełnić jedną repo popełni dla obu, w przeciwnym razie po prostu zadzwoń ChildRepo.Commit również.

Powiązane problemy