Czy mam zwrócić Licznik czy nie?

Wiem, że to może być opinia, ale szukam najlepszych praktyk.

Jak rozumiem, IQueryable<T> implementuje IEnumerable<T>, więc w moim DAL mam obecnie podpisy metody takie jak:

IEnumerable<Product> GetProducts();
IEnumerable<Product> GetProductsByCategory(int cateogoryId);
Product GetProduct(int productId);

Czy powinienem używać IQueryable<T> tutaj?

Jakie są plusy i minusy obu podejść?

Zauważ, że planuję użyć wzorca repozytorium, więc będę miał taką klasę:

public class ProductRepository {

    DBDataContext db = new DBDataContext(<!-- connection string -->);

    public IEnumerable<Product> GetProductsNew(int daysOld) {
        return db.GetProducts()
          .Where(p => p.AddedDateTime > DateTime.Now.AddDays(-daysOld ));
    }
}

Czy powinienem zmienić moje IEnumerable<T> na IQueryable<T>? Jakie są zalety/wady jedno czy drugie?

Author: cdhowie, 2010-06-14

4 answers

To zależy jakie zachowanie chcesz.

  • zwracanie IList mówi dzwoniącemu, że otrzymał wszystkie dane, o które prosił
  • zwrócenie IEnumerable mówi rozmówcy, że będą musieli iterować wynik i może być leniwie załadowany.
  • zwracanie IQueryable mówi dzwoniącemu, że wynik jest wspierany przez dostawcę Linq, który może obsługiwać określone klasy zapytań, nakładając obciążenie na dzwoniącego formularz zapytania wykonującego.

Podczas gdy ta ostatnia daje wywołującemu dużą elastyczność (zakładając, że Twoje repozytorium w pełni je obsługuje), jest najtrudniejsza do przetestowania i, prawdopodobnie, najmniej deterministyczna.

 49
Author: Jim Lamb,
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
2010-06-14 17:14:45

Jeszcze jedna rzecz do przemyślenia: gdzie jest twoje wsparcie przywoławcze / sortujące? Jeśli zapewniasz obsługę stronicowania w repozytorium, zwrócenie IEnumerable<T> jest w porządku. Jeśli stronicujesz poza repozytorium (np. w warstwie kontrolera lub warstwy usługi), to naprawdę chcesz użyć IQueryable<T>, ponieważ nie chcesz ładować całego zbioru danych do pamięci przed jego stronicowaniem.

 6
Author: Ryan,
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
2010-06-17 03:19:35

HUUUGGGE różnica. Widzę to dość często.

Tworzysz IQueryable zanim trafi do bazy danych. IQueryable uderza w DB tylko po wywołaniu funkcji eager (.Na przykład ToList ()) lub rzeczywiście próbujesz wyciągnąć wartości. IQueryable = lazy.

IEnumerable od razu wykona Twoją lambdę przeciwko DB. IEnumerable = chętny.

Co do tego, którego użyć z wzorcem repozytorium, to uważam, że jest chętny. Zwykle widzę ilistów, ale ktoś inaczej będziesz musiał to wyprasować. EDIT-zwykle widzisz IEnumerable zamiast IQueryable, ponieważ nie chcesz, aby warstwy przechodziły obok Twojego repozytorium A) określanie, kiedy dojdzie do trafienia bazy danych lub B) dodawanie dowolnej logiki do łączy poza repozytorium

Jest bardzo dobry filmik LINQ, który bardzo mi się podoba - uderza nie tylko w V IQueryable, ale ma naprawdę fantastyczne insight.

Http://channel9.msdn.com/posts/matthijs/LINQ-Tips-Tricks-and-Optimizations-by-Scott-Allen/

 4
Author: Mike M.,
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
2010-06-14 17:13:59

Możesz użyć IQueryable i zaakceptować, że ktoś może stworzyć scenariusz, w którym może zdarzyć się SELECT N+1. Jest to wada, wraz z faktem, że możesz skończyć z kodem, który jest specyficzny dla Twojej implementacji repozytorium w warstwach nad repozytorium. Zaletą tego jest to, że zezwalasz na wspólne operacje delegowania, takie jak przywoływanie i sortowanie, które mogą być wyrażone poza twoim respository, co łagodzi takie obawy. Jest to również bardziej elastyczny, jeśli trzeba połączyć dane z innymi tabelami bazy danych, ponieważ zapytanie pozostanie wyrażeniem, więc można je dodać przed jego rozwinięciem w zapytanie i trafi do bazy danych.

Alternatywą jest zablokowanie repozytorium tak, aby zwracało zmaterializowane listy przez wywołanie ToList(). W przypadku przykładowego stronicowania i sortowania, będziesz musiał przekazać w pomiń, weź i wyrażenie sortowania jako parametry do metod swojego repozytorium i użyć parametrów, aby zwrócić tylko okno wyniki. Oznacza to, że repozytorium bierze na siebie odpowiedzialność za przywoływanie i sortowanie oraz wszystkie projekcje danych.

To jest trochę osądu, czy dajesz swojej aplikacji moc linq, i mają mniejszą złożoność w repozytorium, czy też kontrolujesz dostęp do danych. Dla mnie zależy to od liczby zapytań powiązanych z każdym podmiotem i kombinacji podmiotów oraz od tego, gdzie chcę zarządzać tą złożonością.

 3
Author: Peter Willis,
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
2010-06-14 20:30:29