ปัญหาดูเหมือนว่าคุณเข้าใจผิดว่า async / await ทำงานกับ Entity Framework อย่างไร
เกี่ยวกับ Entity Framework
ลองดูรหัสนี้:
public IQueryable<URL> GetAllUrls()
{
return context.Urls.AsQueryable();
}
และตัวอย่างการใช้งาน:
repo.GetAllUrls().Where(u => <condition>).Take(10).ToList()
เกิดอะไรขึ้นที่นั่น?
- เราได้รับ
IQueryable
วัตถุ (ยังไม่ได้เข้าถึงฐานข้อมูล) โดยใช้repo.GetAllUrls()
- เราสร้าง
IQueryable
วัตถุใหม่ด้วยเงื่อนไขที่ระบุโดยใช้.Where(u => <condition>
- เราสร้าง
IQueryable
วัตถุใหม่ที่มีขีด จำกัด การเพจที่ระบุโดยใช้.Take(10)
.ToList()
เราเรียกผลจากฐานข้อมูลโดยใช้ IQueryable
วัตถุของเราถูกคอมไพล์เป็น sql (like select top 10 * from Urls where <condition>
) และฐานข้อมูลสามารถใช้ดัชนีได้เซิร์ฟเวอร์ sql ส่งวัตถุเพียง 10 ชิ้นจากฐานข้อมูลของคุณ (ไม่ใช่ทั้งหมดพันล้าน URL ที่เก็บไว้ในฐานข้อมูล)
เอาล่ะมาดูโค้ดแรกกัน:
public async Task<IQueryable<URL>> GetAllUrlsAsync()
{
var urls = await context.Urls.ToListAsync();
return urls.AsQueryable();
}
ด้วยตัวอย่างการใช้งานเดียวกันเราได้รับ:
- เรามีการโหลดในหน่วยความจำทั้งหมดพันล้าน URL
await context.Urls.ToListAsync();
ที่เก็บไว้ในฐานข้อมูลของคุณโดยใช้
- เรามีหน่วยความจำล้น วิธีที่ถูกต้องในการฆ่าเซิร์ฟเวอร์ของคุณ
เกี่ยวกับ async / await
เหตุใดจึงควรใช้ async / await ลองดูรหัสนี้:
var stuff1 = repo.GetStuff1ForUser(userId);
var stuff2 = repo.GetStuff2ForUser(userId);
return View(new Model(stuff1, stuff2));
เกิดอะไรขึ้นที่นี่?
- เริ่มต้นที่บรรทัดที่ 1
var stuff1 = ...
- เราส่งคำขอไปยังเซิร์ฟเวอร์ sql ที่เราต้องการได้รับสิ่งที่ต้องการ
userId
- เรารอ (เธรดปัจจุบันถูกบล็อก)
- เรารอ (เธรดปัจจุบันถูกบล็อก)
- .....
- เซิร์ฟเวอร์ SQL ส่งการตอบสนองถึงเรา
- เราย้ายไปที่บรรทัดที่ 2
var stuff2 = ...
- เราส่งคำขอไปยังเซิร์ฟเวอร์ sql ที่เราต้องการรับ stuff2 สำหรับ
userId
- เรารอ (เธรดปัจจุบันถูกบล็อก)
- และอีกครั้ง
- .....
- เซิร์ฟเวอร์ SQL ส่งการตอบสนองถึงเรา
- เราแสดงมุมมอง
ลองดูเวอร์ชัน async ของมัน:
var stuff1Task = repo.GetStuff1ForUserAsync(userId);
var stuff2Task = repo.GetStuff2ForUserAsync(userId);
await Task.WhenAll(stuff1Task, stuff2Task);
return View(new Model(stuff1Task.Result, stuff2Task.Result));
เกิดอะไรขึ้นที่นี่?
- เราส่งคำขอไปยังเซิร์ฟเวอร์ sql เพื่อรับ stuff1 (บรรทัดที่ 1)
- เราส่งคำขอไปยังเซิร์ฟเวอร์ sql เพื่อรับ stuff2 (บรรทัดที่ 2)
- เรารอการตอบกลับจากเซิร์ฟเวอร์ sql แต่เธรดปัจจุบันไม่ถูกบล็อกเขาสามารถจัดการการสืบค้นจากผู้ใช้รายอื่นได้
- เราแสดงมุมมอง
ทำถูกวิธี
รหัสที่ดีที่นี่:
using System.Data.Entity;
public IQueryable<URL> GetAllUrls()
{
return context.Urls.AsQueryable();
}
public async Task<List<URL>> GetAllUrlsByUser(int userId) {
return await GetAllUrls().Where(u => u.User.Id == userId).ToListAsync();
}
โปรดทราบว่าคุณต้องเพิ่มusing System.Data.Entity
เพื่อใช้วิธีการToListAsync()
IQueryable
IQueryable
หมายเหตุว่าถ้าคุณไม่จำเป็นต้องกรองและเพจและสิ่งที่คุณไม่จำเป็นต้องทำงานร่วมกับ คุณสามารถใช้await context.Urls.ToListAsync()
และทำงานกับรูปธรรมList<Url>
ได้