Я должен возвратить IEnumerable <T> или IQueryable <T> от моего DAL?

Я знаю, что это могло быть мнением, но я ищу лучшие практики.

Поскольку я понимаю, IQueryable<T> реализации IEnumerable<T>, таким образом в моем DAL, у меня в настоящее время есть сигнатуры методов как следующее:

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

Если я использую IQueryable<T> здесь?

Каковы за и против любого подхода?

Обратите внимание, что я - планирование использования шаблона Репозитория, таким образом, у меня будет класс как так:

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 ));
    }
}

Если я изменяю мой IEnumerable<T> кому: IQueryable<T>? Что преимущества/недостатки там одному или другому?

38
задан cdhowie 9 September 2013 в 17:07
поделиться

4 ответа

Это зависит от того, какое поведение вы хотите.

  • Возвращение IList сообщает вызывающей стороне, что они получили все запрошенные данные.
  • Возвращение IEnumerable сообщает вызывающей стороне, что им нужно будет перебрать результат, и он может быть загружен лениво.
  • Возвращение IQueryable сообщает вызывающей стороне, что результат поддерживается поставщиком Linq, который может обрабатывать определенные классы запросов, что возлагает на вызывающую сторону бремя формирования эффективного запроса.

Хотя последний дает вызывающему объекту большую гибкость (при условии, что ваш репозиторий полностью поддерживает его), его труднее всего тестировать и, возможно, он наименее детерминирован.

52
ответ дан 27 November 2019 в 03:37
поделиться

HUUUUGGGE разница. Я это довольно часто вижу.

Вы создаете IQueryable до того, как он попадет в базу данных. IQueryable попадает в БД только после того, как вызывается нетерпеливая функция (например, .ToList ()) или вы действительно пытаетесь извлечь значения. IQueryable = ленивый.

IEnumerable сразу выполнит вашу лямбда-выражение для базы данных. IEnumerable = нетерпеливый.

Что касается того, что использовать с шаблоном репозитория, я считаю, что он очень хочет. Я обычно вижу, как пропускают ILists, но кто-то другой должен будет сгладить это за вас.РЕДАКТИРОВАТЬ - вы обычно видите IEnumerable вместо IQueryable, потому что вы не хотите, чтобы слои прошли мимо вашего репозитория A) определение, когда произойдет попадание в базу данных или B) добавление какой-либо логики к объединениям вне репозитория

Есть очень хорошее видео LINQ что мне очень нравится - это больше, чем просто IEnumerable v IQueryable, но в нем действительно есть фантастическая способность проникновения в суть.

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

5
ответ дан 27 November 2019 в 03:37
поделиться

Еще одна вещь, о которой стоит подумать: где находится поддержка пагинации/сортировки? Если вы обеспечиваете поддержку пагинации внутри вашего репозитория, то возврат IEnumerable вполне подойдет. Если вы используете подкачку вне хранилища (например, в контроллере или на уровне сервиса), то вам действительно нужно использовать IQueryable, потому что вы не хотите загружать весь набор данных в память перед подкачкой.

8
ответ дан 27 November 2019 в 03:37
поделиться

Вы можете использовать IQueryable и принять, что кто-то может создать сценарий, в котором может произойти SELECT N+1. Это недостаток, наряду с тем, что вы можете оказаться с кодом, специфичным для реализации вашего хранилища, в слоях над вашим хранилищем. Преимущество этого способа заключается в том, что вы позволяете выразить такие общие для делегирования операции, как подкачка и сортировка, вне вашего хранилища, тем самым избавляя его от подобных проблем. Это также более гибко, если вам нужно соединить данные с другими таблицами базы данных, так как запрос остается выражением, поэтому его можно дополнять до того, как он будет преобразован в запрос и попадет в базу данных.

Альтернативой является блокировка хранилища таким образом, чтобы оно возвращало материализованные списки путем вызова ToList(). В примере с пагинацией и сортировкой вам нужно будет передать skip, take и выражение сортировки в качестве параметров в методы вашего хранилища, и использовать эти параметры для возврата только окна результатов. Это означает, что хранилище берет на себя ответственность за пейджинг и сортировку, а также за всю проекцию ваших данных.

Это немного оценочное суждение, предоставляете ли вы своему приложению возможности linq и меньшую сложность хранилища, или же вы контролируете доступ к данным. Для меня это зависит от количества запросов, связанных с каждой сущностью и комбинациями сущностей, и от того, где я хочу управлять этой сложностью.

3
ответ дан 27 November 2019 в 03:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: