Возврат IQueryable или перечисляемого объекта


Мне было интересно узнать о разнице в производительности между этими двумя сценариями и о том, какие недостатки могут быть друг у друга?

Первый сценарий:

public class Helper //returns IQueryable
{
   public IQueryable<Customer> CurrentCustomer
   {
      get{return new DataContext().Where(t=>t.CustomerId == 1);
   }
}

public class SomeClass
{
    public void Main()
    {
       Console.WriteLine(new Helper().CurrentCustomer.First().Name;
    }
}

Второй сценарий:

public class Helper //returns Enumerated result
{
   public Customer CurrentCustomer
   {
      get{return new DataContext().First(t=>t.CustomerId == 1);
   }
}

public class SomeClass
{
    public void Main()
    {
       Console.WriteLine(new Helper().CurrentCustomer.Name;
    }
}

Заранее благодарю.

3 4

3 ответа:

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

Например, предположим, что ваш объект Customer имеет несколько больших полей. Используя второй подход, вы всегда будете получать их. Используя первый подход, вы могли бы написать:
string name = helper.CurrentCustomer.Select(x => x.Name).First();

В этом случае потребуется только запросить одно поле в базе данных. С точки зрения времени, запрос будет выполнен только тогда, когда вы действительно запросите данные (именно так это возможно ждать, пока вы не используете Select, чтобы решить, что поместить в запрос в приведенном выше случае). Это имеет свои плюсы и минусы - это может сделать его труднее рассуждать, но это также может сэкономить некоторую работу. С точки зрения" рассуждения о", вы знаете, что как только у вас есть клиент, у вас есть объект, с которым вы можете просто работать. Если вы используете один и тот же объект запроса дважды, вам нужно знать, будет ли ваш поставщик запросов LINQ кэшировать результат... если вы напишете:

IQueryable<Customer> currentCustomerQuery = helper.CurrentCustomer;
Customer x = currentCustomerQuery.First();
Customer y = currentCustomerQuery.First();

Будет ли это выдавать запрос один или два раза? Я подозреваю, что это очень сильно зависит от поставщика, но я не хотел бы делать какие-либо предположения о конкретных.

Еще одна вещь, о которой нужно подумать, - это насколько легко использовать API, который вы создаете. Лично я обычно считаю, что проще использовать API, который дает мне нужные данные, а не запрос, из которого я могу извлечь эти данные. С другой стороны, он немного менее гибок.

Одним из вариантов было бы разрешить обоим - иметь GetCurrentCustomerQuery () и метод GetCurrentCustomer (). (Я, вероятно, не стал бы делать их собственностью сам, но это просто вопрос личного предпочтения.) Таким образом, вы можете получить гибкость, которую вы хотите, когда вам это действительно нужно, но есть простой способ просто получить текущего клиента в качестве объекта.

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

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

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

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