2011-09-21 14 views
11

Oto prawdziwy przykład, który doprowadzi do mojego pytania: Mam AddCommentToArticleCommand, który ma ArticleId, tekst komentarza i adres e-mail. To polecenie:Zapisywanie zmian w jednostkach domen

  • używa repozytorium artykułu, aby uzyskać artykuł (który jest podmiotem domeny)
  • jeśli artykuł nie istnieje, to zwraca article.AddComment (commentText EMAILADDRESS), który doda komentarz do tego artykułu i zgłasza wyjątek, gdy nie może (z powodu nieprawidłowego formatu wiadomości e-mail, artykuł został zamknięty, komentarz nie został wypełniony lub zbyt długo itp.) ...
  • , ale teraz nie wiem, jaki jest najlepszy sposób na zapisanie dodanego komentarza ?

Czy powinienem zrobić coś takiego jak artykułRepository.Save (artykuł)? Ale dlaczego warto zapisać artykuł, jeśli dodano tylko komentarz? Czy mogę zrobić coś takiego jak articleRepository.SaveComment (komentarz), który zapisze tylko komentarz? Albo jakie podejście podejmiesz tutaj?

Dzięki!

Odpowiedz

8

Jako MattDavey Zwraca uwagę, w DDD zwykle myśleć o Aggregate cykl życia, a nie o CRUD problemy z utrzymaniem. Środek i koniec życia Aggregate są obsługiwane przez odpowiadające im Repository. Jeśli chodzi o konkretne pytanie:

, ale teraz nie wiem, jaki jest najlepszy sposób na zapisanie dodanego komentarza?

Najlepszym sposobem radzenia sobie z tym jest znalezienie wiarygodnego ORM i realizować swoje

articles.MakePersistent(article) 

repozytorium przy użyciu tej metody ORM. Dobry ORM wdroży UnitOfWork, będzie zawierać brudne śledzenie, leniwy ładunek i inne problemy związane z trwałością bez ograniczania twoich obiektów domeny. ORM wie, jak uniknąć niepotrzebnego SQL INSERT/UPDATE przy zapisywaniu Aggregate. Twoje obiekty domeny powinny być tak nieustępliwe, jak to tylko możliwe. Jedynym ograniczeniem, na które NHibernate narzuca twoje obiekty, jest to, że powinny one mieć prywatny domyślny konstruktor. Poza tym mogą to być proste obiekty POCO nieświadome wszystkich problemów związanych z utrwalaniem.Aby wyczyścić, obiekty domeny nie powinny mieć flag: IsTransient lub . A jeśli zauważysz, że piszesz kod, który używa tych flag, jesteś reinveting the wheel.

+2

Pomogłeś mi z twoim komentarzem, ponieważ zdałem sobie sprawę, że robię rzeczy, które już istnieją. Więc zmieniłem podejście: używam framework entity z kodem first; i zaimplementowany wzór jednostki pracy. Teraz kontekst EF zachowuje zmiany dla mnie. Dzięki za opinie! –

+0

@Dmitry +1 to bardzo ważny punkt. W moich szczególnych okolicznościach nie mogę przyjąć żadnych założeń dotyczących możliwości użycia ORM (może to nawet nie być ORM), więc sensowne jest dla mnie wdrożenie takich rzeczy, jak śledzenie zmian w domenie. Jeśli jesteś wystarczająco związany z implementacją ORM, że możesz niezawodnie korzystać z jej funkcji, to oczywiście ma to wiele sensu :) – MattDavey

+0

Właściwie moja domena nie jest zależna od ORM ani niczego innego. To centrum architektury cebuli. Jednostka pracy wokół niej jest zależna od ORM i używa jej kontekstu do śledzenia zmian. Ale domena ma tylko logikę domeny ... –

1

W DDD często zdarza się, że bierzesz całą hierarchię kompozycji od zagregowanego rootu i traktujesz ją jako pojedynczą całość. Tak więc, przyjmując tę ​​mentalność, "dlaczego mam zapisać artykuł, jeśli dodano tylko komentarz?", wydaje się, że artykuł jako całość się zmienił, a reprezentacja artykułu w bazie danych jest nieaktualna. Najlepiej byłoby zastąpić całą hierarchię kompozycji w bazie danych (z bazą danych dokumentów byłoby to w porządku), jednak mogłoby to prowadzić do problemów z wydajnością w relacyjnej bazie danych.

W takim przypadku możesz zdecydować o skanowaniu repozytorium nad kompozycją encji, zagregować root i inteligentnie zdecydować, co zrobić z każdym komponentem. Możesz użyć wzorca gościa do iteracji po obiektach komentarzy iw zależności od tego, czy są przejściowe czy brudne, zdecyduj się na wstawienie lub aktualizację, lub po prostu zostaw je w spokoju.

Mam nadzieję, że mam było wystarczająco jasne, nie jestem tak dobry w wyjaśniając rzeczy koncepcyjnych :)

EDIT: Kod próbki:

// In ArticleRepository... 
public void Save(Article article) 
{ 
    // IsTransient (as opposed to IsPersistant) means "has not yet been saved"... 
    if (article.IsTransient) 
    { 
     DB.InsertArticle(article); 
     // Inserting the article also inserts any comments/sub components... 
    } 
    else 
    { 
     // IsDirty means "has been modified since it was taken from the DB"... 
     if (article.IsDirty) 
     { 
      DB.UpdateArticle(article); 
     } 

     foreach(var comment in article.Comments) 
     { 
      if(comment.IsTransient) 
      { 
       DB.InsertComment(article.Id, comment); 
      } 
      else 
      { 
       if (comment.IsDirty) 
       { 
        DB.UpdateComment(comment); 
       } 
      } 
     } 
    } 
} 
+0

Dzięki! Sądzę więc, że oznacza to, że jednostka powinna zaktualizować właściwości IsTransient i IsDirty, jeśli zmieniają się właściwości; a repozytorium jest odpowiedzialne za zresetowanie ich po zapisaniu encji? –

+0

Tak, sprawdź interfejs System.ComponentModel.IChangeTracking. IsTransient/IsPersistant może czasami zostać wydedukowane przez brak/wartość pierwotną wartości klucza odpowiednio. – MattDavey

+0

W moich jednostkach często również implementuję ISupportInitialize, gdy jednostka jest inicjowana, zmiana właściwości nie powoduje, że obiekt jest brudny (lub podnosi właściwość zmieniono wydarzenie itp.). To może być całkiem wygodne :) – MattDavey

Powiązane problemy