最近的一個面試中,被問到IQueryable 和 IEnumerable的區別, 我自己看了一些文章,總結如下:
1. 要明白一點,IQueryable接口是繼承自IEnumerable的接口的.
2. IQueryable中有表達式樹, 這可以看作是它的一個優勢。所以,使用IQueryable操作時,比如對數據的過濾,排序等操作, 這些都會先緩存到表達式樹中. 當對數據庫操作真正發生時,它才會將表達式樹執行來獲取數據。
這也就是說,比如選擇top 2兩行數據, 它會先在表達式樹中緩存這個過濾取top 2的操作。待到操作數據庫時,它就會在數據庫中篩選top 2數據。 =》 IQueryable 有延時加載機制, 它直接從數據庫中篩選數據.
3. IEnumerable, 它對數據進行操作時,和IQueryable不同,它會事先把所有的數據從數據庫獲取,放到內存中。然后,在內存中對這些數據進行篩選操作,包括過濾,排序等. => IEnumerable 在內存中對數據進行篩選
我們通過舉一個用Repository的例子來說明
public class EmployeeRepository : IEmployeeRepository { private readonly CompanyContext _context; public EmployeeRepository(CompanyContext context) { _context = context; } public IEnumerable<Employee> GetIEnumerableEmployees() { return _context.Employees; } public IQueryable<Employee> GetIQueryableEmployees() { return _context.Employees; } }
在Controller中調用
public class HomeController : Controller { private readonly IEmployeeRepository _employeeRepository; public HomeController(IEmployeeRepository employeeRepository) { _employeeRepository = employeeRepository; } public ActionResult Index() { //用IEnumerable返回結果測試 var employees = _employeeRepository.GetIEnumerableEmployees().Take(2); //用IQueryable返回結果測試 // var employees = _employeeRepository.GetIQueryableEmployees().Take(2); return View(employees); } }
使用MiniProfiler來檢測,會發現兩者的區別
使用IEnumerable檢測發現,它在數據庫中執行的語句是:
SELECT [Extent].[Id] AS [Id], [Extent].[Name] AS [Name], [Extent].[Department] AS [Department] FROM [dbo].[Employee] AS [Extent]
可見,它從數據庫中取出了所有數據。然后在內存中再篩選.
使用IQueryable檢測發現,它在數據庫中執行的語句是:
SELECT TOP (2) [Extent].[Id] AS [Id], [Extent].[Name] AS [Name], [Extent].[Department] AS [Department] FROM [dbo].[Employee] AS [Extent]
可見,它只從數據庫中取出了兩條數據