Zagłębiając się w DbContext, DbSet i powiązane interfejsy, zastanawiam się, dlaczego miałbyś zaimplementować oddzielne repozytorium „Generic” wokół tych implementacji?
Wygląda na to, że DbContext i IDbSet robią wszystko, czego potrzebujesz, i zawierają „Unit Of Work” wewnątrz DbContext.
Czy czegoś mi tu brakuje, czy też wydaje się, że ludzie lubią dodawać kolejną warstwę zależności bez powodu.
repository-pattern
entity-framework-4.1
unit-of-work
Code Jammr
źródło
źródło
Odpowiedzi:
Masz rację.
DbContext
jest implementacją wzorca jednostki pracy iIDbSet
jest implementacją wzorca repozytorium.Repozytoria są obecnie bardzo popularne i nadużywane. Wszyscy ich używają tylko dlatego, że istnieją dziesiątki artykułów o tworzeniu repozytorium dla frameworka jednostek, ale nikt tak naprawdę nie opisuje wyzwań związanych z tą decyzją.
Główne powody korzystania z repozytorium to zazwyczaj:
Pierwszym powodem jest pewna czystość architektoniczna i świetny pomysł, że jeśli uniezależnisz swoje wyższe warstwy od EF, możesz później przełączyć się na inną strukturę trwałości. Ile razy widziałeś coś takiego w prawdziwym świecie? Z tego powodu praca z EF jest znacznie trudniejsza, ponieważ repozytorium musi uwidaczniać wiele dodatkowych funkcji opakowujących to, na co domyślnie zezwala EF.
W tym samym czasie zawijanie kodu EF może zapewnić lepszą organizację kodu i przestrzegać reguły oddzielenia obaw. Dla mnie może to być jedyna prawdziwa zaleta repozytorium i jednostki pracy, ale musisz zrozumieć, że przestrzeganie tej reguły z EF może sprawić, że Twój kod będzie łatwiejszy w utrzymaniu i czytelniejszy, ale na początku wysiłek związany z utworzeniem aplikacji będzie znacznie wyższy i w przypadku mniejszych aplikacji może to być niepotrzebna złożoność.
Drugi powód jest częściowo poprawny. Dużą wadą EF jest sztywna architektura, z której trudno jest wyszydzać, więc jeśli chcesz przetestować jednostkową górną warstwę, musisz w jakiś sposób opakować EF, aby umożliwić mockowanie jego implementacji. Ale ma to wiele innych konsekwencji, które tutaj opisałem .
Śledzę bloga Ayende użytkownika . Jeśli kiedykolwiek używałeś NHibernate, prawdopodobnie znasz jego artykuły. Ten facet niedawno napisał kilka artykułów przeciwko używaniu repozytorium z NHibernate, ale NHibernate jest znacznie lepiej do podrobienia.
źródło
IDbSet
, możesz także zdefiniować niestandardowy interfejs w swoim pochodnym kontekście, ale to wszystko. Gdy Twój kod użyje ChangeTracker, Entries lub czegokolwiek innego, opakowanie ich wszystkich będzie wymagało dużego wysiłku.IQueryable
lub akceptujeExpression<>
jako parametr, który jest wewnętrznie wysyłany do zapytania Linq-to-entity, definiujesz logikę poza pozorowanym komponentem z efektami ubocznymi, których nie można przetestować za pomocą testów jednostkowych.Zmagam się z tymi samymi problemami, a makieta do testowania jednostkowego warstw EF jest ważna. Ale natknąłem się na ten świetny artykuł, który wyjaśnia, jak skonfigurować EF 4.1 DbContext, aby był makowalny, upewniając się, że pochodny DbContext zaimplementował ogólny interfejs i uwidacznia IDbSet zamiast DbSet. Ponieważ korzystam z podejścia Database First, ponieważ nasza baza danych już istnieje, po prostu zmodyfikowałem szablony T4 używane do generowania mojego pochodnego DbContext w celu wygenerowania go w celu zwrócenia interfejsów IDbSet, a także wyprowadzenia z mojego interfejsu ogólnego. W ten sposób całość można łatwo wyszydzić i nie trzeba implementować własnej jednostki pracy ani wzorca repozytorium. Po prostu napisz kod usługi, aby wykorzystać ogólny interfejs, a kiedy przejdziesz do testu jednostkowego,
http://refactorthis.wordpress.com/2011/05/31/mock-faking-dbcontext-in-entity-framework-4-1-with-a-generic-repository/
źródło
Jednym z powodów tworzenia repozytorium jest to, że możesz ukryć implementację DBSet i DbContext, jeśli zdecydujesz się przejść z EntityFramework do czegoś innego lub odwrotnie.
Na przykład używałem NHibernate i zawinąłem wszystkie wywołania tego frameworka wewnątrz moich klas repozytorium. Zwracają IEnumerable, aby były „generyczne”, a moje repozytoria mają standardowe operacje CRUD (aktualizacja, usuwanie itp.). Już dawno przeniosłem się do Entity Framework. Robiąc to, nie musiałem niczego zmieniać w moich klasach ViewModel ani poza nimi, ponieważ wskazywały one na moje repozytorium - potrzebowałem tylko zmienić wnętrze mojego repozytorium. To znacznie ułatwiło życie podczas migracji.
(Użyłem NHibernate, ponieważ łączymy się z ISeries, a w tamtym czasie nie było opłacalnych implementacji korzystających z EF z ISeries. Jedyną dostępną metodą było zapłacenie IBM 12 000 USD za DB2Connect)
źródło