Чтобы вернуть IQueryable <T>или нет, вернуть IQueryable <T> - PullRequest
73 голосов
/ 05 апреля 2009

У меня есть класс репозитория, который оборачивает мой LINQ to SQL Data Context. Класс репозитория является классом бизнес-линии, который содержит всю логику уровня данных (и кеширование и т. Д.).

Вот мой v1 моего интерфейса репо.

public interface ILocationRepository
{
    IList<Location> FindAll();
    IList<Location> FindForState(State state);
    IList<Location> FindForPostCode(string postCode);
}

Но для обработки подкачки для FindAll я спорю о том, предоставлять ли IQueryable вместо IList, чтобы упростить интерфейс при таких обстоятельствах, как подкачка.

Каковы преимущества и недостатки предоставления IQueryable из хранилища данных?

Любая помощь очень ценится.

Ответы [ 3 ]

89 голосов
/ 05 апреля 2009

плюсы; компонуемости:

  • абоненты могут добавлять фильтры
  • абоненты могут добавить пейджинг
  • звонящие могут добавить сортировку
  • и т.д.

Минусы; без проверяемость:

  • Ваш репозиторий больше не может быть надлежащим образом проверен юнитами; Вы не можете полагаться на: это работает, b: что делает;
    • вызывающая сторона может добавить непереводимую функцию (т. Е. Нет сопоставления TSQL; разрывы во время выполнения)
    • вызывающий может добавить фильтр / сортировку, которая заставляет его работать как собака
  • Поскольку вызывающие ожидают, что IQueryable<T> будет компонуемым, это исключает нескомпозиционные реализации или заставляет вас написать свой собственный поставщик запросов для них
  • это означает, что вы не можете оптимизировать / профилировать DAL

Для стабильности я взял , а не , выставив IQueryable<T> или Expression<...> в своих репозиториях. Это означает, что я знаю, как ведет себя репозиторий, и мои верхние уровни могут использовать макеты, не беспокоясь "поддерживает ли реальный репозиторий это?" (форсирование интеграционных тестов).

Я все еще использую IQueryable<T> и т. Д. внутри хранилища - но не за границей. Я разместил больше мыслей на эту тему здесь . Настроить параметры подкачки в интерфейсе хранилища также просто. Вы даже можете использовать методы расширения (в интерфейсе) для добавления необязательных параметров подкачки, чтобы у конкретных классов был только один реализуемый метод, но для вызывающей стороны могут быть 2 или 3 перегрузки.

7 голосов
/ 05 апреля 2009

Как уже упоминалось в предыдущем ответе, раскрытие IQueryable дает абонентам доступ к игре с самим IQueryable, что является или может стать опасным.

Первой обязанностью инкапсуляции бизнес-логики является поддержание целостности вашей базы данных.

Вы можете продолжить выставлять IList и можете изменить ваши параметры следующим образом, вот как мы делаем ...

public interface ILocationRepository
{
    IList<Location> FindAll(int start, int size);
    IList<Location> FindForState(State state, int start, int size);
    IList<Location> FindForPostCode(string postCode, int start, int size);
}

если размер == -1, вернуть все ...

Альтернативный способ ...

Если вы все еще хотите вернуть IQueryable, вы можете вернуть IQueryable из List внутри своих функций ... например ...

public class MyRepository
{
    IQueryable<Location> FindAll()
    {
        List<Location> myLocations = ....;
        return myLocations.AsQueryable<Location>;
        // here Query can only be applied on this
        // subset, not directly to the database
    }
}

Первый метод имеет преимущество перед памятью, потому что вы будете возвращать меньше данных вместо всех.

2 голосов
/ 05 апреля 2009

Я рекомендую использовать <strong>IEnumerable</strong> вместо <strong>IList</strong>, с ним вы получите больше гибкости.

Таким образом, вы сможете получить от Db только ту часть данных, которую вы действительно собираетесь использовать без дополнительной работы, проделанной в вашем хранилище.

Пример:

// Repository
public interface IRepository
{
    IEnumerable<Location> GetLocations();
}

// Controller
public ActionResult Locations(int? page)
{
    return View(repository.GetLocations().AsPagination(page ?? 1, 10);
}

Что очень чисто и просто.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...