Подтвердить что ты не робот

Список против IEnumerable vs IQueryable при определении свойства Navigation

Я хочу создать новый объект модели с именем 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; }
}

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

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

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

4b9b3361

Ответ 1

Вы не можете использовать свойство навигации типа 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);
    }
}

Ответ 2

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

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

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

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

|                 | Refine query | Don't change query |
|-----------------|--------------|--------------------|
|  In-memory      |    N/A       |    ICollection     |
|  Lazy execution | IQueryable   |    IEnumerable     |

Ответ 3

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

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

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

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

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

Ответ 4

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

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