web
You’re offline. This is a read only version of the page.
close
Skip to main content

Notifications

Announcements

No record found.

Community site session details

Community site session details

Session Id :

Zastosowanie wzorca repozytorium w programowaniu rozszerzeń systemu Dynamics 365 CE

Piotr Gaszewski Profile Picture Piotr Gaszewski 424

Wprowadzenie

W dzisiejszym odcinku przyjrzymy się zastosowaniu wzorca repozytorium do organizacji dostępu do danych w rozszerzeniach .NET systemu Dynamics 365 CE (pluginy oraz niestandardowe aktywności workflow). W najprostszym przypadku operacje na danych w omawianym systemie możemy wykonywać, korzystając z interfejsu IOrganizationService. Dostęp do stosownego obiektu, który implementuje wspomniany interfejs, zapewnia nam natomiast OrganizationServiceFactory. IOrganizationService daje nam możliwość wykonywania operacji typu CRUD (Create, Retrieve, Update, Delete) na danych oraz kilku innych operacji specyficznych dla systemu Dynamics 365CE (szczegółowe informacje znajdziecie w tym miejscu). Kolejny poziom abstrakcji wprowadza LINQ 2 CRM provider wraz z powiązanymi narzędziami (ServiceContext, klasy Proxy). Wspomniane mechanizmy umożliwiają operowanie na rekordach w systemie Dynamics 365 CE z poziomu kodu w podobny sposób, w jaki robimy to, wykorzystując klasyczne biblioteki ORM.

Repozytorium w rozszerzeniach systemu Dynamics 365

W tym miejscu do głowy może przyjść Wam pytanie: do czego tak naprawdę przydaje się wzorzec repozytorium? Czy z racji dostępności wygodnych technik oraz narzędzi programistycznych wprowadzania kolejnej warstwy abstrakcji jest rzeczywiście przydatne? W moim przekonaniu odpowiedź brzmi: jak najbardziej :). Zastosowanie wspomnianego wzorca umożliwia separację logiki biznesowej od fizycznego dostępu do źródeł danych (usługi sieciowe, bazy danych itp.), wymusza swoiste uporządkowanie kodu odpowiedzialnego za operacje na rekordach w systemie, a przede wszystkim, w powiązaniu z innymi technikami (fabryki, wstrzykiwanie zależności) daje możliwość pisania kodu, który jest niezwykle prosty do automatycznego testowania.

W dalszej części artykułu przyjrzymy się przykładowej implementacji wzorca repozytorium, którą będziemy mogli wykorzystać w naszych rozszerzeniach.

Przykładowa implementacja

W najprostszej wersji interfejs opisujący przykładowe repozytorium, które udostępnia informacje o dostępnych w systemie szansach sprzedaży, może wyglądać w następujący sposób:

Powyższy interfejs opisuje repozytorium udostępniające programistom operacje pobrania rekordu na podstawie znanego identyfikatora oraz utworzenia nowego rekordu szansy sprzedaży w systemie (w celu uproszczenia kodu nie zawiera on innych metod takich jak pobranie kolekcji rekordów na podstawie zadanego zapytania, aktualizacja lub usunięcie rekordu z bazy danych).

Implementacja wspomnianego interfejsu może wyglądać następująco:

Powyższy kod wykorzystuje obiekt OrganizationServiceContext w celu uzyskiwania dostępu do danych. Obiekt ten umożliwia wysyłanie zapytań do systemu, wykorzystując do tego składnie LINQ. Dodatkowo umożliwia operowanie rekordach w kontekście lokalnie oraz zapisanie wszystkich zmian w bazie za pomocą jednorazowego wywołania metody SaveChanges (uwaga, metoda ta nie zapewnia transakcyjności wykonywanych operacji na danych).

Inne podejście do implementacji repozytorium polega na bezpośrednim uruchamianiu metod obiektu OrganizationService. Różnica polega w tym przypadku na tym, że każdorazowe uruchomienie metody repozytorium odwołuje się oraz wywołuje operacje bezpośrednio na serwisie SOAP systemu Dynamics 365. Przykładowy kod repozytorium, które korzysta z obiektu OrganizationService:

W praktyce najczęściej stosuje się podejście mieszane i korzysta z OrganizationService’u lub z kontekstu w miarę potrzeb. 

Wszystko wygląda dobrze. Zauważmy jednak, że kolejne, powiązane z innymi encjami i dodawane do naszego rozwiązania repozytoria będą często zawierać podobny lub nawet identyczny zestaw metod do wykonywania operacji CRUD. Może to prowadzić do pojawiania się w systemie zduplikowanego kodu odpowiedzialnego za wykonywanie identycznych operacji w wielu miejscach. Uniknąć tej sytuacji możemy, tworząc bazowe generyczne repozytorium, po którym będą dziedziczyć inne klasy. Przykładowy interfejs opisujący ww. klasę (ponownie zaprezentuję jego implementację jedynie dla metod GetById oraz Create, nie dla pełnego „kruda”) zamieszczam poniżej.

Implementacja klasy bazowej wygląda natomiast następująco:

Dzięki zastosowaniu powyższej klasy bazowej, implementując repozytorium powiązane z konkretną encją, możemy pominąć podstawowe operacje takie CRUD i skoncentrować się na implementacji metod, specyficznych dla danego typu rekordu.

Poniższy przykład prezentuje przykładowy interfejs IOpportunityRepository oraz implementującą go klasę, która wykorzystuje opisane powyżej komponenty bazowe.

To na razie wszystko na temat wzorca repozytorium. W kolejnych odcinkach przyjrzymy się, w jaki sposób wykorzystać go w połączeniu ze wzorcami fabryki (factory) oraz wstrzykiwania zależności (dependency injection) w celu uzyskania uporządkowanego i testowalnego kodu.

Źródła, które zostały zaprezentowane w tym artykule, znajdziecie pod adresem:

https://github.com/gashupl/dyn365devbestpractices/tree/master/XrmLabs.Blog.Dyn365BestPractices/Chapter%2002/Chapter02.Repositories

Comments

*This post is locked for comments