Apa tujuan AsQuerable ()?

107

Apakah tujuan AsQueryable()hanya agar Anda dapat menyebarkan IEnumerableke metode yang mungkin diharapkan IQueryable, atau adakah alasan yang berguna untuk menyatakan IEnumerablesebagai IQueryable? Misalnya, apakah seharusnya untuk kasus seperti ini:

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

Atau apakah itu benar-benar membuatnya melakukan sesuatu yang berbeda:

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

Apakah IQueryableversi metode ekstensi ini hanya membuat Expression yang akhirnya melakukan hal yang sama setelah dieksekusi? Pertanyaan utama saya adalah, apa kasus penggunaan nyata untuk digunakan AsQueryable?

Ocelot20
sumber

Jawaban:

65

Ada beberapa kegunaan utama.

  1. Seperti yang disebutkan dalam jawaban lain, Anda dapat menggunakannya untuk meniru sumber data yang dapat dikueri menggunakan sumber data dalam memori sehingga Anda dapat lebih mudah menguji metode yang pada akhirnya akan digunakan pada basis yang tidak dapat dihitung IQueryable.

  2. Anda bisa menulis metode pembantu untuk memanipulasi koleksi yang bisa diterapkan ke urutan dalam memori atau sumber data eksternal. Jika Anda menulis metode bantuan untuk digunakan IQueryableseluruhnya, Anda dapat menggunakan AsQueryablesemua enumerabel untuk menggunakannya. Ini memungkinkan Anda untuk menghindari penulisan dua versi terpisah dari metode pembantu yang sangat umum.

  3. Hal ini memungkinkan Anda untuk mengubah jenis waktu kompilasi dari sebuah query yang dapat menjadi sebuah IQueryable, daripada jenis yang lebih diturunkan. Akibatnya; Anda akan menggunakannya pada waktu IQueryableyang sama dengan yang Anda gunakan AsEnumerabledi IEnumerable. Anda mungkin memiliki objek yang diimplementasikan IQueryabletetapi itu juga memiliki Selectmetode instance . Jika itu masalahnya, dan Anda ingin menggunakan Selectmetode LINQ , Anda perlu mengubah jenis waktu kompilasi objek menjadi IQueryable. Anda bisa saja mentransmisikannya, tetapi dengan memiliki AsQueryablemetode Anda dapat memanfaatkan jenis inferensi. Ini akan lebih mudah jika daftar argumen umum kompleks, dan sebenarnya diperlukan jika salah satu argumen umum adalah tipe anonim.

Pelayanan
sumber
Terima kasih untuk kebangkitannya. Menandai ini sebagai jawaban karena ini yang paling lengkap.
Ocelot20
5
Mengingat bahwa IQueryable<T>berasal dari IEnumerable<T>bisakah Anda menjelaskan apa yang Anda maksud dengan "IQuerizable berbasis non-enumerable"?
Dai
2
@Dai Ini mengacu pada IQueryableyang lebih dari sekedar dibungkus IEnumerable, dan yang sebenarnya memanfaatkan kemampuan tambahan IQueryable.
Pelayanan
# 1 persis seperti yang saya cari. Terima kasih telah memverifikasi.
one.beat.consumer
12

Kasus paling valid yang saya miliki untuk AsQueryable adalah pengujian unit. Katakanlah saya memiliki contoh yang dibuat-buat berikut

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

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


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

dan saya ingin menulis pengujian unit untuk memastikan pengontrol mengirimkan kembali hasil yang dikembalikan dari repositori. Ini akan terlihat seperti ini:

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

di mana sebenarnya, semua metode AsQueryable () memungkinkan saya untuk lakukan adalah memuaskan kompilator saat menyiapkan tiruan.

Saya akan tertarik di mana ini digunakan dalam kode aplikasi.

chris
sumber
11

Seperti yang dicatat oleh sanjuro, tujuan dari AsQueryable () dijelaskan dalam Menggunakan AsQuerable With Linq To Objects Dan Linq To SQL . Secara khusus, artikel tersebut menyatakan,

Ini menawarkan manfaat yang sangat baik dalam skenario kata nyata di mana Anda memiliki metode tertentu pada entitas yang mengembalikan IQuer dapat T dan beberapa metode mengembalikan Daftar. Tetapi kemudian Anda memiliki filter aturan bisnis yang perlu diterapkan pada semua koleksi terlepas dari apakah koleksi tersebut dikembalikan sebagai IQuerable dari T atau IEnumerable T.Dari sudut pandang kinerja, Anda benar-benar ingin memanfaatkan eksekusi filter bisnis pada database jika koleksi mengimplementasikan IQuerizable jika tidak mundur untuk menerapkan filter bisnis dalam memori menggunakan LINQ untuk implementasi objek delegasi.

Scott
sumber
6

Tujuan dari AsQueryable () sangat dijelaskan dalam artikel ini Menggunakan AsQuerable With Linq To Objects Dan Linq To SQL

Dari bagian Keterangan MSDN Querizable.AsQuerable Method:

Jika jenis sumber mengimplementasikan IQuerizable, AsQueryable (IEnumerable) mengembalikannya secara langsung. Jika tidak, ia mengembalikan IQuerable yang mengeksekusi kueri dengan memanggil metode operator kueri yang setara di Enumerable, bukan di Querizable.

Itulah tepatnya yang disebutkan dan digunakan dalam artikel di atas. Dalam contoh Anda, ini tergantung pada apa yang dikembalikan orderRepo.GetAll, IEnumerable atau IQuerable (Linq to Sql). Jika ia mengembalikan IQuerizable, metode Count () akan dieksekusi pada database jika tidak maka akan dijalankan dalam memori. Perhatikan baik-baik contoh di artikel referensi.

sanjuro
sumber
3

IQueryableDokumentasi kutipan antarmuka :

Antarmuka IQuerizable dimaksudkan untuk implementasi oleh penyedia kueri.

Jadi bagi seseorang yang bermaksud membuat datastracture-nya dapat di-query dalam .NET, struktur data yang tidak diperlukan tersebut dapat dicacah atau memiliki enumerator yang valid .

IEnumeratoradalah antarmuka untuk iterasi dan pemrosesan aliran data .

Tigran
sumber
Maukah Anda mengulang kalimat ini: "bahwa struktur data yang tidak diperlukan dapat dicacah atau memiliki pencacah yang valid". Saya memahami perbedaan antara IQueryabledan IEnumerable, tetapi saya tidak memahami kasus penggunaan untuk AsQueryablemetode ekstensi. Saya sedikit tersandung pada kalimat itu, yang saya curigai mungkin memiliki jawaban yang saya cari (berdasarkan suara positif).
Ocelot20
@ Ocelot20: itu berarti bahwa struktur data yang disajikan oleh penyedia yang mengimplementasikan IQuerable mungkin tidak menyediakan kemampuan enumerasi. Terserah provider. Mengutip doc: "Kueri yang tidak mengembalikan hasil yang dapat dihitung dieksekusi saat metode Execute dipanggil."
Tigran
Mungkin saya melewatkan sesuatu yang jelas, tetapi saya masih tidak melihat jawaban untuk "mengapa saya harus menggunakan AsQueryable()?" Jika saya memulai dengan IEnumerable (sesuatu yang sudah mampu menyediakan kemampuan enumerasi), mengapa saya perlu mengonversi IQueryablemenggunakan metode ekstensi AsQueryable()? Mungkin contoh kode kecil untuk menggambarkan di mana ini akan berguna? Sepertinya saya melewatkan sesuatu dalam penjelasan Anda. Terima kasih atas waktunya.
Ocelot20
@ Ocelot20: untuk benar-benar menunjukkan perbedaan saya perlu menulis penyedia kueri. Anda tahu bahwa kita memiliki linq to sql, linq to xmldan sebagainya .. jika Anda ingin menulis linqsopir bahwa target Anda strucutres data ( linq to your data), sehingga pengguna dari api Anda akan memiliki kemungkinan untuk menjalankan linqquery terhadap Anda struktur data, Anda harus memilihIQueryable
Tigran
2
Anda sepertinya menjelaskan perbedaan antara IQueryabledan IEnumerable. Saya tahu perbedaannya, dan bukan itu yang saya minta. Saya bertanya mengapa seseorang ingin mengambil sesuatu yang mengimplementasikan IEnumerable, dan mengubahnya menjadi IQueryablemenggunakan AsQueryablemetode ekstensi. Itukah yang Anda jawab? Aku masih tidak tahu ..
Ocelot20