Repository / IQueryable / Query Object

Buduję repozytorium i widziałem w wielu miejscach 2 powody, by nie wystawiać go poza repozytorium.

1) Po pierwsze dlatego, że różni dostawcy LINQ mogą zachowywać się inaczej, a ta różnica powinna być zawarta w repozytorium.

2) drugim jest uniemożliwienie programistom poziomu usług modyfikowania zapytania bazy danych w taki sposób, aby przypadkowo powodowało problemy z wydajnością.

Wydaje mi się, że problemowi 2 można zapobiec tylko przez zachowanie wszystkich zapytań logika w repozytorium i brak możliwości budowania zewnętrznych zapytań? Ale to wydaje mi się trochę niepraktyczne.

Wydaje się, że problem 1 został rozwiązany za pomocą wzorca obiektu danych.

Np. public IEnumerable<T> FindBy(Query query)

Moje pytanie brzmi: dlaczego po prostu nie przepuszczę wyrażenia lambda, ponieważ jest ono niezależne od dostawcy, wydaje się, że zapewnia mi taką samą funkcjonalność jak obiekt zapytania i ten sam poziom separacji?

Np. public IEnumerable<T> FindBy(Expression<Func<T,bool>> predicate)

Czy Jest jakiś powód żeby tego nie robić? Czy to łamie jakieś zasady? Najlepsze praktyki? o czym powinienem wiedzieć?

Author: Dale Burrell, 2012-08-15

2 answers

Po prostu zwróć IQueryable<T>.

Zanim napiszesz kolejny fragment "kodu repozytorium", znacząco skorzystasz z przeczytania artykułu Ayende Architecting in The Pit of Doom - The Evils of the repozytorium Abstraction Layer

Twoje podejście jest bez wątpienia dodawaniem znacznej niepotrzebnej złożoności.

Cały kod z drugiego pytania na ogólnej listy OrderBy Lambda nie robi nic innego niż maskowanie istniejącego skutecznego API z niepotrzebną i nieznaną abstrakcją.

Jeśli chodzi o Wasze obawy,

  1. Dostawcy LINQ zachowują się inaczej, ale dopóki przekazywane predykaty mogą być przetwarzane przez dostawcę LINQ, nie ma to znaczenia. W przeciwnym razie nadal napotkasz ten sam problem, ponieważ przekazujesz Expression, Który i tak przechodzi do IQueryable. Jeśli implementacja IQueryProvider nie może obsłużyć twojego predykatu, to nie może zajmij się swoim orzeczeniem. (Zawsze możesz wywołać ToList(), jeśli musisz ocenić przed dalszym filtrowaniem, którego nie można przetłumaczyć).

  2. Modyfikacja zapytania może powodować problemy z wydajnością, ale jest bardziej prawdopodobne, że ujawni bardzo potrzebne funkcje. Co więcej, problemy z wydajnością poniesione przez nieoptymalne zapytanie LINQ mogą być znacznie mniej szkodliwe niż problemy z wydajnością poniesione przez pobranie o wiele większej liczby rekordów niż potrzeba, aby uniknąć ujawnienia IQueryable lub poprzez systematyczne filtrowanie logiki dostępu do danych przez nadęte poziomy abstrakcji, które tak naprawdę nic nie robią (pierwsze zagrożenie jest bardziej znaczące). Ogólnie rzecz biorąc, nie będzie to problemem, ponieważ większość wiodących dostawców LINQ zoptymalizuje logikę zapytań w procesie tłumaczenia.

Jeśli chcesz ukryć logikę zapytań z przodu, nie próbuj tworzyć ogólnego repozytorium. Enkapsulate zapytań z rzeczywistych metod specyficznych dla biznesu. Teraz Ja może się mylę, ale zakładam, że użycie wzorca repozytorium jest inspirowane przez Domain Driven Design. Jeśli tak jest, to powodem korzystania z repozytorium jest umożliwienie utworzenia domeny z głównym naciskiem na model domeny. Jednak używanie tego rodzaju repozytorium generycznego nie robi nic więcej niż zmiana semantyki z Create Read Update Delete na Find Add Remove Save. Nie ma tam żadnej prawdziwej wiedzy biznesowej.

Rozważ sensowność (i usability) z

interface IPersonRepository 
{ 
     Person GetById(int id);
     IEnumerable<Person> FindByName(string firstName, string lastName);
}

W przeciwieństwie do

interface IRepository<T> { 
     IEnumerable<T> FindBy(Query<T> query);
}

Ponadto, czy rzeczywiście można wskazać na korzyść korzystania z IRepository<T> w ogóle (w przeciwieństwie do IQueryable<T>)?

Należy również wziąć pod uwagę, że przy podejściu ogólnym, w rzeczywistości nie enkapsulujesz logiki zapytań w ogóle. W końcu budujesz go zewnętrznie, co doprowadzi do dodatkowych niepotrzebnych kodów.

* Jeszcze jedna uwaga na temat zasobów, które odradzają używanie IQueryable<T>, jest taka, że warto przyjrzeć się Data ich publikacji. Był czas, kiedy dostępność dostawców LINQ była dość ograniczona (do wczesnych EF i LINQ-to-SQL). W tym czasie ujawnienie IQueryable<T> wiązałoby się z niekompatybilnością z niektórymi popularniejszymi zamiennikami Microsoft ORM (LINQ-to-NHibernate już dawno zostało zaimplementowane). W tym momencie Wsparcie LINQ jest praktycznie wszechobecne w poważnych bibliotekach ORM. NET

 19
Author: smartcaveman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:07:22

W przeciwieństwie do odpowiedzi panującej powyżej, wyraźnym punktem sprzeciwu byłoby testowanie jednostkowe . Zwracanie prostego generycznego IQueryable jest nieszczelną abstrakcją dla każdego klienta, który ma dostęp do jego wywołania. Nie ma ograniczeń dla metody repozytorium, więc nic do stwierdzenia w teście jednostkowym.

Użycie IQueryable prawie na pewno zależy od kontekstu samej aplikacji i architektury. Na przykład, jeśli pracujesz nad osobistym projektem samodzielnie, możesz bezpiecznie przyjmij odpowiedzialność za władanie tą nieograniczoną mocą, nie obciążając nikogo poza sobą. Jeśli jednak pracujesz nad aplikacją dla firmy, której kod wchodzi do produkcji, z pewnością jest więcej interesariuszy niż ty. W tym scenariuszu możesz pracować w warstwie dostępu do danych i próbować kodować w oparciu o użycie kodu przez innych programistów. Teraz musisz kontrolować, co wchodzi i wychodzi, aby nie złamali Twojego kodu, a ty nie złamiesz ich. To jest motywacja, a testowanie jednostkowe jest egzekwowaniem.

Mając to powiedziane, nie używaj po prostu IQueryable<T>. Użyj tego, co ma sens dla Twojej aplikacji.

 0
Author: PeterG,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-27 17:52:10