很多人對於操作 EF 有一些疑慮,只要夠了解他,就可以避掉效能問題、陷阱,所以我會陸陸續續整理了一些使用 EF 不小心會犯的錯誤,以便提醒自己不要犯錯
本文連結
外部連結
不要把 IQueryable 直接拿去跑迴圈
using (var dbContext = new NorthwindDbContext())
{
var count = 0;
foreach (var category in dbContext.Categories)
{
foreach (var product in category.Products)
{
if (category.CategoryID == product.CategoryID)
{
count++;
}
}
}
Console.WriteLine($"找到了{count}次");
}
來,我們來看一下為什麼不好,設定中斷觀察一下,第一段的 foreach 就把所有的 category 都拿回來了。
延遲執行要用 ToList 或是 for 以及其他例執行的方法,才會真的觸發 SQL 查詢
第二段的 foreach,再去拿一次 Product,裡面有幾筆 category,就拿幾次的 Product
這裡是消極式載入所觸發的 SQL 命令可以這樣寫
using (var dbContext = new NorthwindDbContext())
{
var queryable = from category in dbContext.Categories
join product in dbContext.Products on category.CategoryID equals product.CategoryID
select new { category, product };
var count = 0;
foreach (var item in queryable)
{
if (item.category.CategoryID == item.product.CategoryID)
{
count++;
}
}
Console.WriteLine($"找到了{count}次");
}
或是這樣
using (var dbContext = new NorthwindDbContext())
{
var categories = dbContext.Categories.Include("Products");
var count = 0;
foreach (var category in categories)
{
foreach (var product in category.Products)
{
if (category.CategoryID == product.CategoryID)
{
count++;
}
}
}
Console.WriteLine($"找到了{count}次");
}
小心定義 IEnumerable 型別所引發的問題
這裡把 employeeFromDb 變數的型別設計成 IEnumerable<Employee>
using (var dbContext = new NorthwindDbContext())
{
IEnumerable<Employee> employeesFromDb = from employee in dbContext.Employees
where employee.BirthDate > new DateTime(1900, 1, 1)
select employee;
var employeesFromMemory = from employee in employeesFromDb
orderby employee.EmployeeID
select employee;
employeesFromMemory.Dump("排序在Memory排");
}
這有甚麼問題?
可以看到應用程式並沒有送出 order by 的命令
因為 employeesFromDb 定義成 IEnumerable<Employee>,所以 employeesFromDb 變成 LINQ to Objects,就不會再套用後面的 EF 查詢設定。
執行到 var employeesFromMemory = from employee in employeesFromDb,employeesFromDb 就會把所有的資料撈回來,然後才進行記憶體排序
應該怎麼寫,只要把 employeeFromDb 的型別改成 var,讓它自動判別型別 IQueryable<Employee> 即可
using (var dbContext = new NorthwindDbContext())
{
var employeesFromDb = from employee in dbContext.Employees
where employee.BirthDate > new DateTime(2012,1,1)
select employee;
var employeesFromMemory = from employee in employeesFromDb
orderby employee.EmployeeID
select employee;
employeesFromMemory.Dump("排序在DB排");
}
可以看到 order by 的命令有送出了
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET