Список против IEnumerable против IQueryable при определении свойства Navigation - PullRequest
14 голосов
/ 12 февраля 2012

Я хочу создать новый объект модели с именем Movie_Type в моем веб-приложении ASP.NET MVC.Каковы будут различия, если я определю свойство навигации этого класса как List, ICollection или IQueryable следующим образом?

public partial class Movie_Type
{ 
    public int Id { get; set; }
    public string Name { get; set; } 
    public string Description { get; set; } 
    public List<Movie> Movies { get; set; }
}

ИЛИ

public partial class Movie_Type
{ 
    public int Id { get; set; }
    public string Name { get; set; } 
    public string Description { get; set; } 
    public IQueryable<Movie> Movies { get; set; }
}

ИЛИ

public partial class Movie_Type
{
    public int Id { get; set; }
    public string Name { get; set; } 
    public string Description { get; set; } 
    public ICollection<Movie> Movies { get; set; }
}

Редактировать: - @ Томас Петричек.Спасибо за ваш ответ.в моем случае я использую подход базы данных сначала, а затем я использую шаблон DbContext для сопоставления моих таблиц, который автоматически создал ICollection для всех свойств навигации, поэтому мои вопросы: - 1. Значит ли это, что это не так?всегда лучший выбор для использования Icollection.И я должен изменить автоматически сгенерированные классы, чтобы лучше всего соответствовать моему случаю.2. Во-вторых, я могу выбирать между отложенной или быстрой загрузкой, определяя .include, например

var courses = db.Courses.Include(c => c.Department);

Независимо от того, что я использую для определения свойств навигации.Так что я не могу понять вашу точку зрения.3. Я не нашел ни одного примера или учебника, которые бы использовали IQuerable для определения свойств навигации. В чем может быть причина?BR

Ответы [ 4 ]

15 голосов
/ 13 февраля 2012

Нельзя использовать свойство навигации типа IQueryable<T>.Вы должны использовать ICollection<T> или некоторый тип коллекции, который реализует ICollection<T> - например, List<T>.(IQueryable<T> не реализует ICollection<T>.)

Свойство навигации - это просто объект или коллекция объектов в памяти, либо оно null, либо коллекция пуста.

Он никогда не загружается из базы данных при загрузке родительского объекта, который содержит свойство навигации из базы данных.

Вы должны либо явно указать, что хотите загрузить свойство навигации вместе с родительским объектом, который является нетерпеливая загрузка :

var movieTypes = context.Movie_Types.Include(m => m.Movies).ToList();
// no option to filter or sort the movies collection here.
// It will always load the full collection into memory

Или она будет загружена отложенной загрузкой (которая включена по умолчанию, если ваше свойство навигации virtual):

var movieTypes = context.Movie_Types.ToList();
foreach (var mt in movieTypes)
{
    // one new database query as soon as you access properties of mt.Movies
    foreach (var m in mt.Movies)
    {
        Console.WriteLine(m.Title);
    }
}

Последний вариант - явная загрузка , которая наиболее близка к вашему намерению.

var movieTypes = context.Movie_Types.ToList();
foreach (var mt in movieTypes)
{
    IQueryable<Movie> mq = context.Entry(mt).Collection(m => m.Movies).Query();
    // You can use this IQueryable now to apply more filters
    // to the collection or sorting, for example:
    mq.Where(m => m.Title.StartWith("A"))   // filter by title
      .OrderBy(m => m.PublishDate)          // sort by date
      .Take(10)                             // take only the first ten of result
      .Load();                              // populate now the nav. property
    // again this was a database query

    foreach (var m in mt.Movies)    // contains only the filtered movies now
    {
        Console.WriteLine(m.Title);
    }
}
8 голосов
/ 12 февраля 2012

Есть два возможных взгляда на вещи:

  1. Сохраняется ли результат в памяти как часть экземпляра объекта?
    Если вы выберете ICollection, результат будет сохранен в памяти - это может быть не очень хорошей идеей, если набор данных очень большой или вам не всегда нужно получать данные. С другой стороны, когда вы сохраняете данные в памяти, вы можете изменять набор данных из вашей программы.

  2. Можете ли вы уточнить запрос, отправляемый на сервер SQL?
    Это означает, что вы сможете использовать LINQ над возвращенным свойством, и дополнительные операторы LINQ будут переведены в SQL - если вы не выберете эту опцию, дополнительная обработка LINQ будет выполняться в памяти.

Если вы хотите сохранить данные в памяти, вы можете использовать ICollection. Если вы хотите уточнить запрос, вам нужно использовать IQueryable. Вот сводная таблица:

|                 | Refine query | Don't change query |
|-----------------|--------------|--------------------|
|  In-memory      |    N/A       |    ICollection     |
|  Lazy execution | IQueryable   |    IEnumerable     |
0 голосов
/ 20 января 2014

Коллекция, которую структура сущностей фактически создает для вас, если вы используете виртуальные навигационные свойства, реализует ICollection, но не IQueryable, поэтому вы не можете использовать IQueryable для своих навигационных свойств, как говорит Слаума.

Вы можете определять свои свойства как IEnumerable, поскольку ICollection расширяет IEnumerable, но если вы сделаете это, вы потеряете возможность добавлять новые дочерние элементы в эти свойства навигации.

0 голосов
/ 12 февраля 2012

Больше стандарта IEnumerable, так как это наименее распространенный знаменатель.

Iqueryable может быть возвращен, если вы хотите, чтобы вызывающая сторона получила дополнительные функции запросов, не имея 10 методов хранилища для обработки различных сценариев запросов.

Недостатком является то, что ienumerable может медленно 'считать ()', но если объект реализует ICollection, этот интерфейс сначала проверяется на это значение без необходимости перечисления всех элементов.

Также имейте в виду, что если вы вернете iqueryable ненадежному абоненту, он может выполнить некоторые вызовы и вызовы методов для iqueryable и получить доступ к контексту, соединению, строке соединения, выполненным запросам и т. Д.

Также обратите внимание, что nhibernate, например, имеет объект запроса, который вы можете передать в хранилище, чтобы указать параметры. С платформой сущностей вам нужно вернуть IQueryable для улучшения критериев запроса

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