Яка мета AsQueryable ()?


107

Чи є мета, AsQueryable()щоб ви могли перейти IEnumerableдо методів, які можуть очікувати IQueryable, чи є корисна причина, щоб представити IEnumerableяк IQueryable? Наприклад, чи належить це для таких випадків:

IEnumerable<Order> orders = orderRepo.GetAll();

// I don't want to create another method that works on IEnumerable,
// so I convert it here.
CountOrders(orders.AsQueryable());

public static int CountOrders(IQueryable<Order> ordersQuery)
{
    return ordersQuery.Count();
}

Або це насправді змушує робити щось інше:

IEnumerable<Order> orders = orderRepo.GetAll();
IQueryable<Order> ordersQuery = orders.AsQueryable();

IEnumerable<Order> filteredOrders = orders.Where(o => o.CustomerId == 3);
IQueryable<Order> filteredOrdersQuery = ordersQuery.Where(o => o.CustomerId == 3);

// Are these executed in a different way?
int result1 = filteredOrders.Count();
int result2 = filteredOrdersQuery.Count();

Чи IQueryableверсії цих методів розширення просто створюють вираз, який в кінцевому підсумку робить те саме, щойно виконується? Моє головне питання - що таке справжній випадок використання AsQueryable?

Відповіді:


65

Є кілька основних цілей.

  1. Як згадується в інших відповідях, ви можете використовувати його для знущання з джерелом даних, що піддається перегляду, використовуючи джерело даних в пам'яті, щоб ви могли легше протестувати методи, які в кінцевому підсумку будуть використовуватися на нечисельній основі IQueryable.

  2. Ви можете написати допоміжні методи для маніпулювання колекціями, які можуть застосовуватися як до послідовностей в пам'яті, так і до зовнішніх джерел даних. Якщо ви пишете свої довідкові методи для IQueryableповного використання, ви можете просто скористатись AsQueryableусіма перелічними номерами, щоб використовувати їх. Це дозволяє уникнути написання двох окремих версій дуже узагальнених допоміжних методів.

  3. Це дозволяє змінити тип часу компіляції, що підлягає запиту IQueryable, а не якийсь більш похідний тип. В ефекті; ви б використовували його IQueryableв той самий час, який ви використовували AsEnumerableв IEnumerable. У вас може бути об’єкт, який реалізує, IQueryableале також має Selectметод екземпляра . Якщо це було так, і ви хотіли використовувати Selectметод LINQ , вам потрібно буде змінити тип часу компіляції об'єкта на IQueryable. Ви можете просто віддати це, але, маючи AsQueryableметод, ви можете скористатися висновком типу. Це просто зручніше, якщо список загальних аргументів є складним, і це фактично необхідно, якщо будь-який із загальних аргументів має анонімний тип.


Дякую за відродження. Позначення цього як відповідь, оскільки воно є найбільш повним.
Ocelot20

5
З огляду на те , що IQueryable<T>відбувається від IEnumerable<T>ласка , ви можете пояснити , що ви маєте в виду під "не-лічильної основою IQueryable»?
Дай

2
@Dai Це стосується того, IQueryableщо більше, ніж просто загорнуте IEnumerable, і що фактично використовує додаткові можливості IQueryable.
Сервіс

№1 - саме те, чого я домагався. Дякуємо за підтвердження.
one.beat.consumer

12

Найбільш правдивий випадок, який я маю для AsQueryable, - це тестування одиниць. Скажіть, я маю такий дещо надуманий приклад

public interface IWidgetRepository
{
   IQueryable<Widget> Retrieve();
} 

public class WidgetController
{
   public IWidgetRepository WidgetRepository {get; set;}


   public IQueryable<Widget> Get()
   {
      return WidgetRepository.Retrieve();
   }
}

і я хочу написати блок-тест, щоб переконатися, що контролер передає результати, повернені з сховища. Це виглядатиме приблизно так:

[TestMethod]
public void VerifyRepositoryOutputIsReturned()
{    
    var widget1 = new Widget();
    var widget2 = new Widget();
    var listOfWidgets = new List<Widget>() {widget1, widget2};
    var widgetRepository = new Mock<IWidgetRepository>();
    widgetRepository.Setup(r => r.Retrieve())
      .Returns(listOfWidgets.AsQueryable());
    var controller = new WidgetController();
    controller.WidgetRepository = widgetRepository.Object;

    var results = controller.Get();

    Assert.AreEqual(2, results.Count());
    Assert.IsTrue(results.Contains(widget1));
    Assert.IsTrue(results.Contains(widget2));
}

де дійсно, весь метод AsQueryable () дозволяє мені задовольнити компілятор під час налаштування макету.

Мені було б цікаво, де це використовується в коді програми.


11

Як зазначає sanjuro, мета AsQueryable () пояснюється у використанні AsQueryable With Linq To Objects та Linq To SQL . Зокрема, у статті зазначено:

Це дає чудові переваги в сценаріях реальних слів, де у вас є певні методи для сутності, які повертають IQueyable від T, а деякі методи повертають Список. Але тоді у вас є фільтр правил бізнесу, який потрібно застосувати до всієї колекції, незалежно від того, чи повертається колекція як IQueyable від T або IEnumerable of T. З точки зору ефективності, ви дійсно хочете скористатися виконанням бізнес-фільтра в базі даних, якщо колекція реалізує IQueryable інакше відступає, щоб застосувати фільтр бізнесу в пам'яті за допомогою Linq для об'єкта реалізації делегатів.


6

Призначення AsQueryable () значно пояснено в цій статті Використання AsQueryable з Linq до об'єктів і Linq в SQL

З розділу Зауваження MSDN Queryable.AsQueryable метод:

Якщо тип джерела реалізує IQueryable, AsQueryable (IEnumerable) повертає його безпосередньо. В іншому випадку він повертає IQueryable, який виконує запити, викликаючи еквівалентні оператори методів операторів запитів у «Перелічуваному», а не «Queryable».

Саме про це йдеться і використовується в цій статті. У вашому прикладі це залежить від того, що є orderRepo.GetAll, що повертається, IEnumerable або IQueryable (Linq to Sql). Якщо він повертає IQueryable, метод Count () буде виконаний на базі даних, інакше він буде виконаний у пам'яті. Подивіться уважно на приклад у статті, що посилається.


3

IQueryableДокументація, що цитує інтерфейс :

Інтерфейс IQueryable призначений для реалізації постачальниками запитів.

Отже, для того, хто має намір зробити свою структуру даних доступною для пошуку в .NET, та структура, яка не потрібна, може бути перерахована або мати дійсний нумератор .

IEnumeratorце інтерфейс для ітерації та обробки потоку даних .


Ви заперечуєте перефразовуючи це: "та структура даних, яка не потрібна, може бути перерахована або мати дійсний нумератор". Я розумію різницю між IQueryableі IEnumerable, але не розумію випадку використання AsQueryableметоду розширення. Я трохи заплутався в цьому реченні, але, мабуть, може відповісти, яку я шукаю (виходячи з підсумків).
Ocelot20

@ Ocelot20: така структура даних капелюхів, представлена ​​постачальником, який реалізує IQueryable, може не забезпечити можливості перерахування. Це залежить від постачальника. Цитуючи doc: "Запити, які не повертають перелічених результатів, виконуються, коли викликається метод Execute."
Тигран

Можливо, я пропускаю щось очевидне, але я все ще не бачу відповіді на те, "навіщо мені це потрібно використовувати AsQueryable()?" Якщо я починаю з IEnumerable (щось вже здатне забезпечити можливість перерахування), навіщо мені потрібно переходити до IQueryableметоду розширення AsQueryable()? Може, невеликий приклад коду, щоб проілюструвати, де це стане в нагоді? Здається, у вашому поясненні чогось не вистачає. Дякую за ваш час.
Оцелот20

@ Ocelot20: щоб дійсно показати різницю, мені потрібно написати постачальника запитів. Ви знаєте, що у нас є linq to sql, linq to xmlі так .. якщо ви хочете написати linqдрайвер, який націлений на ваші структури даних ( linq to your data), тож користувачі вашої програми матимуть змогу запускати linqзапити до ваших структур даних, ви повинні вибратиIQueryable
Tigran,

2
Ви, здається, пояснюєте різницю між IQueryableі IEnumerable. Я знаю різницю, і це не те, про що я прошу. Я питаю , чому хтось - то хотів взяти що - то , що знаряддя IEnumerable, і перетворити його в IQueryableвикористанні AsQueryableметод розширення. Це ви відповідаєте? Я досі не можу сказати ..
Ocelot20
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.