Uważam, że jeśli masz repozytoria, użyj ORM, który jest już wystarczająco abstrakcyjny z bazy danych.
Jednak tam, gdzie teraz pracuję, ktoś uważa, że powinniśmy mieć warstwę, która wyodrębnia ORM na wypadek, gdybyśmy chcieli później zmienić ORM.
Czy to naprawdę konieczne, czy po prostu dużo pracy nad stworzeniem warstwy, która będzie działać na wielu ORM?
Edytować
Aby podać więcej szczegółów:
- Mamy klasy POCO i Entity Class, które są mapowane za pomocą AutoMapper. Klasa encji jest używana przez warstwę repozytorium. Warstwa repozytorium wykorzystuje następnie dodatkową warstwę abstrakcji do komunikacji z Entity Framework.
- Warstwa biznesowa w żaden sposób nie ma bezpośredniego dostępu do Entity Framework. Nawet bez dodatkowej warstwy abstrakcji nad ORM, ta musi korzystać z warstwy usługi, która korzysta z warstwy repozytorium. W obu przypadkach warstwa biznesowa jest całkowicie oddzielona od ORM.
- Głównym argumentem jest możliwość zmiany ORM w przyszłości. Ponieważ jest on naprawdę zlokalizowany wewnątrz warstwy repozytorium, dla mnie jest już dobrze oddzielony i nie rozumiem, dlaczego potrzebna jest dodatkowa warstwa abstrakcji, aby mieć kod „jakości”.
Odpowiedzi:
W ten sposób leży szaleństwo. Jest bardzo mało prawdopodobne, że kiedykolwiek będziesz musiał zmienić ORM. A jeśli kiedykolwiek zdecydujesz się zmienić ORM, koszt przepisywania mapowań będzie niewielkim ułamkiem kosztów opracowania i utrzymania własnej meta-ORM. Spodziewałbym się, że możesz napisać kilka skryptów, aby wykonać 95% pracy potrzebnej do zmiany ORM.
Wewnętrzne ramy prawie zawsze są katastrofą. Budowanie w oczekiwaniu na przyszłe potrzeby jest niemal gwarantowaną katastrofą. Udane ramy są pobierane z udanych projektów, a nie budowane z wyprzedzeniem w celu zaspokojenia wyimaginowanych potrzeb.
źródło
ORM zapewnia abstrakcję, aby warstwa danych była niezależna od RDBMS, ale może nie wystarczyć, aby „oddzielić” warstwę biznesową od warstwy danych. W szczególności nie należy zezwalać obiektom mapowanym na tabele RDBMS na „wyciek” bezpośrednio do warstwy biznesowej.
Warstwa biznesowa musi co najmniej zaprogramować interfejsy, które potencjalnie mogą zarządzać obiekty mapowane w tabeli ORM z warstwy danych. Ponadto może być konieczne utworzenie opartej na interfejsie warstwy abstrakcyjnego budynku zapytania, aby ukryć natywne możliwości zapytań w ORM. Głównym celem jest uniknięcie „wypalenia” dowolnego ORM do twojego rozwiązania poza jego warstwą danych. Na przykład kuszące może być tworzenie ciągów HQL ( Hibernate Query Language ) w warstwie biznesowej. Jednak ta z pozoru niewinna decyzja wiązałaby warstwę biznesową z Hibernacją, łącząc w ten sposób warstwy biznesowe i warstwy dostępu do danych; powinieneś starać się unikać tej sytuacji w jak największym stopniu.
EDYCJA: W twoim przypadku dodatkowa warstwa w repozytorium jest stratą czasu: w oparciu o punkt drugi, twoja warstwa biznesowa jest wystarczająco izolowana od repozytorium. Zapewnienie dodatkowej izolacji wprowadziłoby niepotrzebną złożoność, bez dodatkowych korzyści.
Problem z budowaniem dodatkowej warstwy abstrakcji w repozytorium polega na tym, że konkretna „marka” ORM dyktuje sposób interakcji z nią. Jeśli zbudujesz cienkie opakowanie, które wygląda jak Twoja ORM, ale jest pod twoją kontrolą, zastąpienie leżącej poniżej ORM będzie mniej więcej tak trudne, jak byłoby bez tej dodatkowej warstwy. Z drugiej strony, jeśli budujesz warstwę, która nie przypomina niczego w rodzaju ORM, powinieneś zakwestionować swój wybór technologii mapowania relacyjno-obiektowego.
źródło
UnitOfWork zazwyczaj zapewnia tę abstrakcję. Jest to jedno miejsce, które musi się zmienić, twoje repozytoria zależą od niego za pośrednictwem interfejsu. Jeśli kiedykolwiek będziesz musiał zmienić O / RM, po prostu zaimplementuj nowy UoW. Jeden i gotowe.
BTW to coś więcej niż zmiana O / RM, pomyśl o testowaniu jednostkowym. Mam trzy implementacje UnitOfWork, jedną dla EF, jedną dla NH (ponieważ faktycznie DID musiałem przełączać O / RM w trakcie projektu dla klienta, który chciał obsługiwać Oracle), i jedną dla trwałości InMemory. Trwałość InMemory była idealna do testów jednostkowych, a nawet do szybkiego prototypowania, zanim byłam gotowa umieścić bazę danych.
Ramy są łatwe do wdrożenia. Najpierw masz ogólny interfejs IRepository
I interfejs IUnitOfWork
Następnie znajduje się podstawowe repozytorium (wybór, czy ma być abstrakcyjny)
Wdrażanie IUnitOfWork jest dziecinnie proste dla EF, NH i In Memory. Powód, dla którego zwracam IQueryable, jest z tego samego powodu, o czym Ayende wspomniał w swoim poście, że klient może dalej filtrować, sortować, grupować, a nawet wyświetlać wyniki za pomocą LINQ, a Ty nadal korzystasz z tego po stronie serwera.
źródło