Sorun, zaman uyumsuz / beklemenin Entity Framework ile nasıl çalıştığını yanlış anladığınız gibi görünüyor.
Entity Framework hakkında
Öyleyse, şu koda bakalım:
public IQueryable<URL> GetAllUrls()
{
return context.Urls.AsQueryable();
}
ve kullanım örneği:
repo.GetAllUrls().Where(u => <condition>).Take(10).ToList()
Orada ne olur?
IQueryable
Kullanarak nesne alıyoruz (henüz veritabanına erişmiyoruz)repo.GetAllUrls()
IQueryable
Kullanarak belirtilen koşulda yeni bir nesne oluşturuyoruz.Where(u => <condition>
IQueryable
Kullanarak belirtilen sayfalama sınırına sahip yeni bir nesne oluşturuyoruz.Take(10)
- Kullanarak veritabanından sonuçları alırız
.ToList()
. Bizim IQueryable
nesne (gibi sql için derlendi select top 10 * from Urls where <condition>
). Ve veritabanı dizinleri kullanabilir, sql sunucusu size veritabanınızdan yalnızca 10 nesne gönderir (veritabanında depolanan milyarlarca url'nin tamamı değil)
Tamam, ilk koda bakalım:
public async Task<IQueryable<URL>> GetAllUrlsAsync()
{
var urls = await context.Urls.ToListAsync();
return urls.AsQueryable();
}
Aynı kullanım örneğiyle elde ettik:
- Kullanarak veritabanınızda depolanan tüm milyar url'leri belleğe yüklüyoruz
await context.Urls.ToListAsync();
.
- Hafıza taşması var. Sunucunuzu öldürmenin doğru yolu
Async / await hakkında
Async / await neden kullanılması tercih edilir? Bu koda bakalım:
var stuff1 = repo.GetStuff1ForUser(userId);
var stuff2 = repo.GetStuff2ForUser(userId);
return View(new Model(stuff1, stuff2));
Burada ne oluyor?
- 1. satırdan başlayarak
var stuff1 = ...
- Bir şeyler almak istediğimiz sql sunucusuna istek gönderiyoruz1.
userId
- Bekleriz (mevcut konu bloke edilir)
- Bekleriz (mevcut konu bloke edilir)
- .....
- Sql sunucusu bize yanıt gönder
- 2. satıra geçiyoruz
var stuff2 = ...
- Bir şeyler almak istediğimiz sql sunucusuna istek gönderiyoruz2 için
userId
- Bekleriz (mevcut konu bloke edilir)
- Ve yeniden
- .....
- Sql sunucusu bize yanıt gönder
- Görünüm oluşturuyoruz
Şimdi bunun eşzamansız bir sürümüne bakalım:
var stuff1Task = repo.GetStuff1ForUserAsync(userId);
var stuff2Task = repo.GetStuff2ForUserAsync(userId);
await Task.WhenAll(stuff1Task, stuff2Task);
return View(new Model(stuff1Task.Result, stuff2Task.Result));
Burada ne oluyor?
- Malzeme almak için sql sunucusuna istek gönderiyoruz (1. satır)
- Stuff2'yi almak için sql sunucusuna istek gönderiyoruz (2. satır)
- Sql sunucusundan yanıtları bekliyoruz, ancak mevcut iş parçacığı bloke edilmedi, başka kullanıcıların sorularını halledebilir
- Görünüm oluşturuyoruz
Bunu yapmanın doğru yolu
Burada çok iyi kod:
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();
}
IQueryable using System.Data.Entity
yöntemini kullanmak ToListAsync()
için eklemeniz gerekenden fazlasını unutmayın .
Unutmayın, filtrelemeye, sayfalandırmaya vb IQueryable
. İhtiyacınız yoksa, çalışmanıza gerek yoktur . Sadece await context.Urls.ToListAsync()
materyalize kullanabilir ve çalışabilirsiniz List<Url>
.