2010-08-09 21 views
10

Zacząłem myśleć o śledzeniu zmian w złożonym grafie obiektów w odłączonej aplikacji. Znalazłem już kilka rozwiązań, ale chciałbym wiedzieć, czy istnieje jakaś najlepsza praktyka lub jakiego rozwiązania używasz i dlaczego? Przekazałem to samo pytanie MSDN forum, ale otrzymałem tylko jedną odpowiedź. Chciałbym uzyskać więcej odpowiedzi na podstawie doświadczeń innych programistów.Śledzenie zmian na skomplikowanym obiekcie graficznym

To pytanie jest związane z .NET, więc odpowiedzi na pytania dotyczące implementacji preferuję odpowiedzi związane ze światem .NET, ale myślę, że jest tak samo na innych platformach.

Problem teoretyczny w moim przypadku jest zdefiniowana w wielu warstwowej architektury (niekoniecznie n-tier w tej chwili), jak następuje:

  • Warstwa repozytoriów wykorzystaniem ORM do czynienia z uporem (narzędzie ORM nie w tej chwili, ale najprawdopodobniej będzie to Entity Framework 4.0 lub NHibernate).
  • Zestaw czystych klas (persistent ignorant = POCO, który jest odpowiednikiem POJO w świecie Java) reprezentujących obiekty domeny. Repozytoria zachowują te klasy i zwracają je jako wyniki zapytań.
  • Zestaw usług domenowych współpracujących z domenami.
  • Warstwa fasady definiująca bramę do logiki biznesowej. Wewnętrznie używa repozytoriów, usług domenowych i obiektów domeny. Obiekty domeny nie są odsłonięte - każda metoda elewacji używa zestawu wyspecjalizowanych obiektów przesyłania danych dla parametru i wartości zwracanej. Obowiązkiem każdej metody elewacji jest przekształcenie domeny na DTO i odwrotnie.
  • Nowoczesna aplikacja internetowa wykorzystująca warstwę elewacji i DTO - tę aplikację rozłączam. Zasadniczo projektowanie może się zmienić w przyszłości, aby warstwa fasady była opakowana przez warstwę usługi WWW, a aplikacja internetowa zużyje te usługi => przejście na trójwarstwowe (sieć, logika biznesowa, baza danych).

Załóżmy teraz, że jednym z obiektów domeny jest Zamówienie, które zawiera szczegóły zamówienia (wiersze) i powiązane zamówienia. Kiedy klient żąda Zlecenia na edycję, może modyfikować Zamówienie, dodawać, usuwać lub modyfikować szczegóły Zamówienia oraz dodawać lub usuwać powiązane Zamówienia. Wszystkie te modyfikacje są wykonywane na danych w przeglądarce internetowej - javascript i AJAX. Wszystkie zmiany są następnie przesyłane jednym kliknięciem, gdy klient naciska przycisk zapisu. Pytanie brzmi, jak poradzić sobie z tymi zmianami? Narzędzia repozytorium i narzędzia ORM muszą wiedzieć, które jednostki i relacje zostały zmodyfikowane, wstawione lub usunięte. Skończyłem z dwoma "najlepszymi" rozwiązaniami:

  1. Przechowywać stan początkowy DTO w ukrytym polu (w najgorszym przypadku sesji). Po otrzymaniu żądania zapisania zmian utwórz nowy DTO na podstawie odebranych danych i drugiego DTO na podstawie utrwalonych danych. Połącz tych dwóch i śledź zmiany. Wyślij połączone DTO do warstwy elewacji i użyj otrzymanych informacji o zmianach, aby prawidłowo skonfigurować wykres jednostek. Wymaga to ręcznego śledzenia zmian w obiekcie domeny, dzięki czemu informacje o zmianach mogą być konfigurowane od podstaw, a następnie przekazywane do repozytorium - to jest kwestia, z której nie jestem zadowolony.

  2. Nie śledzić zmian w DTO. Po otrzymaniu zmodyfikowanych danych w warstwie elewacji utwórz zmodyfikowany obiekt i załaduj aktualny stan z repozytorium (generalnie dodatkowe zapytanie do bazy danych - to jest punkt, z którego nie jestem zadowolony) - scalenie tych dwóch elementów i automatyczne śledzenie zmian za pomocą proxy podmiotu udostępnianego przez narzędzie ORM (Na to pozwala framework Entity 4.0 i NHibernate). Podczas obsługi współbieżności należy zachować szczególną ostrożność, ponieważ rzeczywisty stan nie musi być stanem początkowym.

Co o tym sądzisz?Co polecasz?

Wiem, że niektórych z tych wyzwań można uniknąć, używając buforowania na niektórych warstwach aplikacji, ale jest to coś, czego nie chcę obecnie używać.

Moje zainteresowanie tym tematem idzie nawet dalej. Załóżmy na przykład, że aplikacja przechodzi do architektury trójwarstwowej, a klient (aplikacja internetowa) nie zostanie zapisany w klasach .NET = DTO nie można ponownie użyć. Śledzenie zmian w DTO będzie znacznie trudniejsze, ponieważ wymagać będzie, aby inny zespół programistów prawidłowo wdrożył mechanizm śledzenia w swoich narzędziach programistycznych.

Uważam, że te problemy muszą zostać rozwiązane w wielu aplikacjach, podziel się doświadczeniem.

Odpowiedz

3

Chodzi o odpowiedzialność.

(Nie jestem pewien, czy to jest odpowiedź, której szukasz - daj mi znać, jeśli nie, mogę ją zaktualizować).

Mamy więc wiele warstw w systemie - każdy jest odpowiedzialny za inne zadanie: dostęp do danych, interfejs użytkownika, logikę biznesową itp. Kiedy tworzymy system w ten sposób, próbujemy (między innymi) próbować uczynić przyszłość Zmień łatwość, tworząc każdy komponent odpowiedzialny za jedno zadanie - aby mógł skupić się na tym jednym zadaniu i zrobić to dobrze. Ułatwia także modyfikację systemu w miarę upływu czasu i zmiany.

Podobne rozważania należy wziąć pod uwagę, rozważając DTO - "jak śledzić zmiany?" na przykład. Oto, jak do niego podchodzę: BL odpowiada za zarządzanie regułami i logiką; biorąc pod uwagę bezpaństwową naturę sieci (w której wykonuję większość mojej pracy) po prostu nie śledzę stanu obiektu i nie patrzę wprost na zmiany. Jeśli użytkownik przekazuje dane z powrotem (aby je zapisać/zaktualizować), przekażę całą ich część bez dbania o to, co zostało zmienione.

Jedna dłoń może wydawać się nieskuteczna, ale ponieważ ilość danych nie jest duża, to po prostu nie jest problemem; z drugiej strony mniej ruchomych części mniej może pójść źle, ponieważ proces jest znacznie prostszy.

W jaki sposób przekazuję dane? -

  • Używam DTO (a może POCO byłoby bardziej dokładne); kiedy wymieniam dane między BL i DAL (poprzez interfejsy/DI) dane są wymieniane jako DTO (lub ich kolekcja). W szczególności używam struct dla pojedynczej instancji i kolekcji tych struktur dla wielu.

  • DTO są zdefiniowane we wspólnej klasie, która ma bardzo mało zależności.

  • Rozmyślnie staram się ograniczyć liczbę DTO do stworzenia dla konkretnego obiektu (np. "Zamówienie") - ale w tym samym czasie będę tworzyć nowe, jeśli jest ku temu dobry powód. Zazwyczaj będę miał "gruby" DTO, który zawiera większość/wszystkie dane dostępne dla tego obiektu, prawdopodobnie również będę miał znacznie bardziej szczupły, który został zaprojektowany do użycia w kolekcjach (dla list itp.). W obu przypadkach te DTO to czysta informacja o powrocie do "czytania". Musisz pamiętać o obowiązkach - kiedy BL prosi o dane, zwykle nie próbuje zapisać danych w tym samym czasie; więc fakt, że DTO jest "tylko do odczytu", bardziej dotyczy zgodności z czystym interfejsem i architekturą niż regułą biznesową.

  • Zawsze definiuję oddzielne DTO dla wstawiania i aktualizowania - nawet jeśli mają one dokładnie te same pola. W ten sposób najgorsze, co może się zdarzyć, jest powielenie jakiegoś kodu triwalnego - w przeciwieństwie do posiadania zaległości i wielokrotnych przypadków ponownego użycia w celu rozplątania.

Na koniec - nie należy mylić działania DAL z interfejsem użytkownika; Niech ORM wykonają swoje zadanie, tylko dlatego, że przechowują dane w określony sposób, nie oznacza to, że jest to jedyny sposób.

Najważniejsze jest określenie konkretnych interfejsów między warstwami.

Zarządzanie tym, co się zmieniło, jest zadaniem BL; pozwól, aby interfejs działał w sposób, który jest najlepszy dla twoich użytkowników i pozwól BL zrozumieć, jak chce sobie z tym poradzić, a DAL (za pomocą twojego miłego, czystego interfejsu z DI) robi to, co zostało powiedziane.

+1

Witam, dziękuję za bardzo dobrą odpowiedź. Lubię to. Jest bardzo blisko mojej architektury, z tym wyjątkiem, że w moim przypadku używam DTO między UI a BL i obiektami/obiektami Domain między BL i DAL. Rozumiem twoje wyjaśnienie Jedyny punkt, którego mi brakuje to odpowiedź na główne pytanie - jak śledzić zmiany na złożonym grafiku obiektu? Otrzymujesz DTO i musisz jakoś znaleźć to, co się zmieniło. Jeśli twój DTO jest prostym obiektem, nie musisz go śledzić, ale co z DTO, który zawiera zbiór innych DTO? Musisz wiedzieć, co zmieniło się w tej kolekcji. –

+0

RE zmian w obiekcie Wykres - oczekuję Istnieją wzorce projektowe, które poradzą sobie z tym, ale nie mogę sobie przypomnieć z góry mojej głowy - Momento przychodzi mi do głowy, inaczej może być modelem napędzanym zdarzeniami? –

+0

W tradycyjnym modelu ASP.NET strony są zwykle budowane od zera za każdym razem (a więc ładujesz wszystkie dane bez względu na to, co się zmieniło), a jeśli zachowujesz dane w widoku, to traktujesz to jako "dane" - więc nie byłem w stanie chcieć szukać konkretnych zmian w sposobie, w jaki sugerujesz (?). Inne podejście jest oparte na technologii AJAX, ale jest podobne.Wzrok obserwatora również może być interesujący. –

3

Nasza architektura jest bardzo podobna do twojej, ale używa klienta Silverlight zawierającego te same obiekty domenowe (że nie ma dokładnego - kod jest udostępniany) na kliencie i serwerze. Główne punkty naszej architektury jest w krótkim

  • Klient ma model domeny i zmiany są śledzone za pomocą mojego własne ramy realizowane śledzenia (używa AOP tak, że można używać Poços po stronie klienta; nie wiem znam ramy tego i chcę, aby model domeny był trwałym ignorantem)
  • Cały ten model jest przechowywany w pewnym rodzaju zdalnego repozytorium na kliencie. Kiedy zapiszemy te zmiany, drzewo zmian zostanie wyodrębnione (przez moją strukturę śledzenia zmian) i przetłumaczone w DTO (dokładnie DataContracts, ale to nie ma znaczenia) przy użyciu asemblerów. DTO posiadają flagę stanu śledzenia (nowe, zmodyfikowane, usunięte).
  • Po stronie serwera (warstwa usługi jest implementowana przez usługi WCF), DTO są tłumaczone na obiekty domeny i dołączane do ORM (NHibernate w naszym przypadku). Z powodu tego procesu przywiązania potrzebuję stanu śledzenia. Następnie można wprowadzić i kontynuować dodatkowe zmiany za pomocą ORM

Obecnie trudno jest dołączyć do ORM skomplikowane wykresy, ale mam nadzieję, że powodem jest to, że nie mamy dużego doświadczenia w korzystaniu z NHibernate.

Nie jesteśmy jeszcze skończeni, ale wydaje się obiecujący.

Aby uzyskać dostęp do danych, próbowaliśmy użyć usługi WCF Dataservices. Ale nie sądzę, że będziemy z nich korzystać, ponieważ wymaganiem jest użycie DataContract. Prowadzi to do tłumaczenia z zapytań LINQ opartych na DataContract na zapytania LINQ oparte na obiekcie domenowym. To nie jest poręczne i zbyt trudne do wdrożenia, jeśli model domeny i datacrracts różnią się bardzo (tak będzie w przypadku niektórych iteracji).

Wszelkie uwagi?

Powiązane problemy