Niedawno przeczytałem, że stosowanie wzorca repozytorium w połączeniu z ORM nie jest dobrą praktyką. Z mojego zrozumienia wynika, że abstrakcja, którą zapewniają w bazie danych SQL, jest zbyt nieszczelna, aby mogła zostać zawarta we wzorcu.
Mam kilka pytań na ten temat:
Co robisz, jeśli chcesz zmienić ORM? Miałbyś kod specyficzny dla ORM w swojej aplikacji, gdybyś nie zawierał go w repozytorium.
Czy wzorzec repozytorium jest nadal prawidłowy, gdy nie używasz ORM i sam używasz ADO.NET do dostępu do danych i zapełniania danych obiektowych?
Jeśli używasz ORM, ale nie wzorca repozytorium, gdzie przechowujesz często używane zapytania? Czy mądrze byłoby reprezentować każde zapytanie jako klasę i mieć jakąś fabrykę zapytań do tworzenia instancji?
design-patterns
orm
repository
użytkownik 1450877
źródło
źródło
Odpowiedzi:
1) To prawda, ale jak często zmieniasz ORM?
2) Powiedziałbym tak, ponieważ kontekst ORM jest swego rodzaju repozytorium i kryje w sobie wiele pracy związanej z tworzeniem zapytań, wyszukiwaniem danych, mapowaniem itp. Jeśli nie używasz ORM, ta logika wciąż musi gdzieś znajdować się. Nie wiem jednak, czy kwalifikowałoby się to jako wzorzec repozytorium w najściślejszym znaczeniu tego słowa ...
3) Często enkapsuluję zapytania, ale zwykle jest to więcej do celów testowania / stubowania. Poza tym byłbym ostrożny przy ponownym użyciu zapytania w różnych częściach aplikacji, ponieważ wtedy ryzykujesz powstanie zależności od czegoś, co może zmienić n-razy (n to liczba miejsc, w których używasz zapytania).
źródło
Nie byłem jeszcze w sytuacji, gdy firma nagle postanowiła zmienić technologię dostępu do danych. Jeśli tak się stanie, konieczne będą pewne prace. Mam tendencję do abstrakcyjnego dostępu do danych poprzez interfejsy. Repozytorium jest jednym ze sposobów rozwiązania tego problemu.
Miałbym wtedy inny zestaw do konkretnej implementacji mojej warstwy dostępu do danych. Na przykład mogę mieć:
Company.Product.Data
iCompany.Product.Data.EntityFramework
zespoły. Pierwszy zestaw byłby używany wyłącznie do interfejsów, a inny byłby konkretnym wdrożeniem logiki dostępu do danych Entity Framework.Myślę, że to ty decydujesz, który wzór jest ważny, czy nie. Użyłem wzorca repozytorium w warstwie prezentacji. Należy pamiętać, że ludzie lubią wrzucać obowiązki do repozytoriów. Zanim się zorientujesz, twoja klasa repozytorium będzie tańczyć, śpiewać i robić różne rzeczy. Chcesz tego uniknąć.
Widziałem klasę repozytorium, która zaczęła się od odpowiedzialności za GetAll, GetById, Update i Delete, co jest w porządku. Do czasu zakończenia projektu ta sama klasa dysponowała dziesiątkami metod (obowiązków), których nigdy nie powinno być. Na przykład GetByForename, GetBySename, UpdateWithExclusion i wszelkiego rodzaju szalone rzeczy.
Tutaj pojawiają się zapytania i polecenia.
Myślę, że bardzo dobrym pomysłem jest stosowanie zapytań i poleceń zamiast repozytoriów. Wykonuję następujące czynności:
Zdefiniuj interfejs dla zapytania. Pomoże to w teście jednostkowym. Na przykład
public interface IGetProductsByCategoryQuery { ... }
Zdefiniuj konkretną implementację zapytania. Będziesz mógł wstrzykiwać je za pośrednictwem wybranych ram IoC. Na przykład
public class GetProductsByCategoryQuery : IGetProductsByCategoryQuery
Teraz zamiast zanieczyszczać repozytorium dziesiątkami obowiązków, po prostu grupuję moje zapytania w przestrzeni nazw. Na przykład interfejs dla powyższego zapytania może istnieć w:
Company.SolutionName.Products.Queries
a implementacja może istniećCompany.SolutionName.Products.Queries.Implementation
Jeśli chodzi o aktualizację lub usuwanie danych, używam wzorca poleceń w ten sam sposób.
Niektórzy mogą się nie zgodzić i powiedzieć, że zanim projekt zostanie ukończony, będziesz mieć dziesiątki klas i przestrzeni nazw. Tak, będziesz. Moim zdaniem to dobrze, że możesz przeglądać wybrane przez siebie rozwiązanie w IDE i od razu zobaczyć, jakie obowiązki ma dany komponent. Jeśli zamiast tego zdecydowałeś się zastosować wzorzec repozytorium, będziesz musiał zajrzeć do każdej klasy repozytorium, próbując wywiązać się ze swoich obowiązków.
źródło
ZASTRZEŻENIE: To, co następuje, oparte jest na moim zrozumieniu i krótkim doświadczeniu z tego wzorca (to znaczy Repozytorium). Może robię to źle ... w rzeczywistości jestem całkiem pewny, że robię to źle :). Tak więc, choć jest to próba odpowiedzi, jest to również pytanie ukryte.
Używam wzorca repozytorium, aby wyodrębnić warstwę dostępu do danych, która w większości przypadków jest ORM. Jest to ogólny interfejs z metodami tworzenia, odczytu, aktualizacji, usuwania i implementacji klas LINQ na SQL i EF. Mógłbym wykonać implementację, która zapisuje do plików XML na dysku (po prostu dziki przykład tego, co mogłem z tym zrobić). Nie wdrażam jednostki pracy, ponieważ jest ona obsługiwana przez ORM. W razie potrzeby prawdopodobnie mógłbym to wdrożyć. Podoba mi się to w ten sposób, ponieważ do tej pory zapewniło mi przyjemną separację. Nie twierdzę, że nie ma lepszych alternatyw.
Aby odpowiedzieć na pytania:
Aby dać wam inny przykład, chłopaki z Umbraco wyodrębnili pojemnik DI, na wypadek gdyby chcieli przejść na coś innego.
źródło
Jeśli ORM oferuje elastyczność LINQ, chętny ładowanie itp., Nie ukryłbym tego za żadną dodatkową warstwą.
Jeśli dotyczy to surowego sql (mikro ORM), to i tak należy użyć „metody na zapytanie”, aby uzyskać możliwość ponownego użycia, dzięki czemu wzór repozytorium jest dobrze dopasowany.
Dlaczego musiałbyś się zmienić?
Należy użyć tej, która ma większość potrzebnych funkcji. Możliwe, że nowa wersja ormX wprowadza nowe funkcje i okazuje się lepsza niż obecna, ale ...
Jeśli zdecydujesz się ukryć orm, możesz korzystać tylko z funkcji wspólnych dla wszystkich kandydatów.
Np. Nie możesz używać
Dictionary<string, Entity>
właściwości w swoich bytach, ponieważ ormY nie może sobie z nimi poradzić.Zakładając LINQ jest używany, większość z przełącznikiem ORM jest tylko przełączanie referencje biblioteki i zastąpienie
session.Query<Foo>()
zcontext.Foos
lub podobny aż kompiluje. Nudne zadanie, ale zajmuje mniej czasu niż kodowanie warstwy abstrakcji.Tak. Kod powinien być wielokrotnego użytku, co oznacza umieszczenie budynku SQL, materializacji obiektu itp. W jednym miejscu (osobna klasa). Równie dobrze możesz nazwać klasę „XRepository” i wyodrębnić z niej interfejs.
Zakładając, że użyto LINQ, opakowanie klasy byłoby przesadą IMHO. Lepszym sposobem byłyby metody rozszerzenia
Każdy kod, który jest używany w wielu miejscach (lub ma potencjał) i jest wystarczająco skomplikowany (podatny na błędy), powinien zostać wyodrębniony w scentralizowane miejsce.
źródło