AsQueryable () มีจุดประสงค์อะไร?


109

มีจุดประสงค์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คืออะไร?

คำตอบ:


67

การใช้งานหลักมีไม่กี่อย่าง

  1. ตามที่ระบุไว้ในคำตอบอื่น ๆ ที่คุณสามารถใช้มันเพื่อเยาะเย้ยแหล่งข้อมูล queryable IQueryableโดยใช้แหล่งข้อมูลในหน่วยความจำเพื่อให้คุณสามารถได้อย่างง่ายดายมากขึ้นวิธีการทดสอบว่าในที่สุดจะนำไปใช้กับที่ไม่ใช่นับตาม

  2. คุณสามารถเขียนวิธีการตัวช่วยสำหรับจัดการคอลเลกชันที่สามารถใช้กับลำดับในหน่วยความจำหรือแหล่งข้อมูลภายนอก หากคุณเขียนวิธีการช่วยเหลือของคุณเพื่อใช้IQueryableทั้งหมดคุณสามารถใช้AsQueryableกับตัวนับทั้งหมดเพื่อใช้งานได้ วิธีนี้ช่วยให้คุณหลีกเลี่ยงการเขียนวิธีการช่วยเหลือทั่วไปสองเวอร์ชันแยกกัน

  3. ช่วยให้คุณสามารถเปลี่ยนประเภทเวลาคอมไพล์ของแบบสอบถามเป็น an IQueryableแทนที่จะเป็นประเภทที่ได้รับมากกว่าบางประเภท ส่งผลกับ; คุณจะใช้ในIQueryableเวลาเดียวกันกับที่คุณใช้AsEnumerableกับIEnumerableไฟล์. คุณอาจมีวัตถุที่ใช้งานIQueryableแต่ก็มีSelectวิธีการเช่นกัน หากพบว่ากรณีและคุณต้องการที่จะใช้ LINQ วิธีการที่คุณจะต้องเปลี่ยนชนิดรวบรวมเวลาของวัตถุที่Select IQueryableคุณสามารถโยนมันได้ แต่ด้วยAsQueryableวิธีการที่คุณสามารถใช้ประโยชน์จากการอนุมานประเภทได้ สิ่งนี้จะสะดวกกว่าหากรายการอาร์กิวเมนต์ทั่วไปมีความซับซ้อนและจำเป็นจริงๆหากอาร์กิวเมนต์ทั่วไปใด ๆ เป็นประเภทที่ไม่ระบุตัวตน


ขอบคุณสำหรับการฟื้นฟู ทำเครื่องหมายว่านี่คือคำตอบเนื่องจากเป็นคำตอบที่สมบูรณ์ที่สุด
Ocelot20

5
เนื่องจากได้IQueryable<T>มาจากIEnumerable<T>คุณสามารถอธิบายความหมายของ "IQueryable ตามที่ไม่สามารถระบุได้" ได้หรือไม่
Dai

2
@Dai มันหมายถึงสิ่งIQueryableที่เป็นมากกว่าการห่อหุ้มIEnumerableและใช้ประโยชน์จากความสามารถเพิ่มเติมของIQueryableไฟล์.
Servy

# 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 ด้วย Linq วัตถุและ LINQ กับ SQL โดยเฉพาะอย่างยิ่งบทความระบุว่า

สิ่งนี้ให้ประโยชน์ที่ยอดเยี่ยมในสถานการณ์จำลองคำจริงที่คุณมีวิธีการบางอย่างในเอนทิตีที่ส่งคืนค่าที่เป็นประโยชน์ของ T และวิธีการบางอย่างส่งคืนรายการ แต่คุณมีตัวกรองกฎทางธุรกิจที่ต้องใช้กับคอลเล็กชันทั้งหมดไม่ว่าคอลเลกชันจะถูกส่งคืนเป็น IQueryable ของ T หรือ IEnumerable ของ T. จากจุดยืนประสิทธิภาพคุณต้องการใช้ประโยชน์จากการดำเนินการตัวกรองธุรกิจบนฐานข้อมูลถ้า คอลเลกชันดำเนินการ IQueryable มิฉะนั้นจะถอยกลับไปใช้ตัวกรองธุรกิจในหน่วยความจำโดยใช้ Linq เพื่อคัดค้านการนำผู้รับมอบสิทธิ์ไปใช้


6

วัตถุประสงค์ของ AsQueryable () มีคำอธิบายอย่างมากในบทความนี้การใช้ AsQueryable ด้วย Linq To Objects และ Linq To SQL

จากส่วนหมายเหตุของ MSDN Queryable AsQueryable Method:

หากประเภทของแหล่งที่มาใช้ IQueryable AsQueryable (IEnumerable) จะส่งกลับโดยตรง มิฉะนั้นจะส่งคืน IQueryable ที่ดำเนินการสืบค้นโดยเรียกเมธอดตัวดำเนินการเคียวรีที่เท่ากันใน Enumerable แทนที่จะเป็นใน Queryable

นั่นคือสิ่งที่กล่าวถึงและใช้ในบทความข้างต้น ในตัวอย่างของคุณขึ้นอยู่กับสิ่งที่เป็น orderRepo.GetAll return, IEnumerable หรือ IQueryable (Linq to Sql) หากส่งคืน IQueryable เมธอด Count () จะดำเนินการบนฐานข้อมูลมิฉะนั้นจะดำเนินการในหน่วยความจำ ดูตัวอย่างในบทความอ้างอิงอย่างละเอียด


3

IQueryableเอกสารการอ้างอิงอินเทอร์เฟซ:

อินเทอร์เฟซ IQueryable มีไว้สำหรับการใช้งานโดยผู้ให้บริการสืบค้น

ดังนั้นสำหรับคนที่มีความตั้งใจที่จะทำให้ queryable datastracture ใน .NET, datastructure ที่ว่าไม่จำเป็นสามารถระบุหรือมีการแจงนับที่ถูกต้อง

IEnumeratorเป็นอินเทอร์เฟซสำหรับการทำซ้ำและประมวลผลสตรีมข้อมูลแทน


คุณช่วยกรุณาเปลี่ยนข้อความนี้: "โครงสร้างข้อมูลที่ไม่จำเป็นสามารถระบุได้หรือมีตัวระบุที่ถูกต้อง" ฉันเข้าใจความแตกต่างระหว่างIQueryableและIEnumerableแต่ฉันไม่เข้าใจกรณีการใช้งานสำหรับAsQueryableวิธีการขยาย ฉันรู้สึกสะดุดกับประโยคนั้นเล็กน้อยซึ่งฉันสงสัยว่าอาจมีคำตอบที่ฉันกำลังมองหา (ขึ้นอยู่กับการโหวตเพิ่มคะแนน)
Ocelot20

@ Ocelot20: นั่นหมายถึงโครงสร้างข้อมูลหมวกที่นำเสนอโดยผู้ให้บริการที่ใช้ IQueryable อาจไม่สามารถให้ความสามารถในการแจงนับ ขึ้นอยู่กับผู้ให้บริการ Quoting doc: "การสืบค้นที่ไม่ส่งคืนผลลัพธ์ที่สามารถระบุได้จะถูกดำเนินการเมื่อเรียกเมธอด Execute"
Tigran

บางทีฉันอาจพลาดบางอย่างที่ชัดเจน แต่ฉันยังไม่เห็นคำตอบว่า "ทำไมฉันถึงต้องใช้AsQueryable()" ถ้าฉันเริ่มต้นด้วยการ IEnumerable (สิ่งที่มีอยู่แล้วสามารถในการให้ความสามารถในการแจงนับ) ทำไมฉันจะต้องแปลงที่จะIQueryableใช้วิธีการขยายAsQueryable()? อาจเป็นตัวอย่างโค้ดขนาดเล็กเพื่อแสดงให้เห็นว่าสิ่งนี้จะมีประโยชน์อย่างไร? ฉันดูเหมือนจะขาดอะไรบางอย่างในคำอธิบายของคุณ ขอบคุณที่สละเวลา.
Ocelot20

@ Ocelot20: เพื่อแสดงความแตกต่างจริงๆฉันต้องเขียนผู้ให้บริการแบบสอบถาม คุณจะรู้ว่าเรามีlinq to sql, linq to xmlและอื่น ๆ .. ถ้าคุณต้องการที่จะเขียนlinqโปรแกรมควบคุมที่เป้าหมายของคุณ strucutres ข้อมูล ( linq to your data) ดังนั้นผู้ใช้ API ของคุณจะมีความเป็นไปได้ที่จะเรียกใช้linqแบบสอบถามกับคุณโครงสร้างข้อมูลที่คุณต้องเลือกIQueryable
Tigran

2
ดูเหมือนว่าคุณจะอธิบายความแตกต่างระหว่างและIQueryable IEnumerableฉันรู้ถึงความแตกต่างและนั่นไม่ใช่สิ่งที่ฉันขอ ฉันกำลังถามว่าทำไมใครบางคนถึงต้องการใช้สิ่งที่ใช้IEnumerableและแปลงเป็นIQueryableโดยใช้AsQueryableวิธีการขยาย นั่นคือสิ่งที่คุณกำลังตอบ? ยังบอกไม่ได้ ..
Ocelot20
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.