EF(EntityFramework)原理:屬於ORM的一種實現
通過edmx文件來查看三部分:概念模型,數據模型,映射關系,上下文DbContext完成連接、狀態跟蹤管理,核心類是EntityClient完成映射
EF(EntityFramework)延遲加載:
>1:EF查詢默認會延遲加載
>2:EF對於集合類型的導航屬性會延遲加載
本質:IQueryable擁有3個成員,Expression,Type,Provider
IQueryable與IEnumberable對比區別:
IQueryable: 可以拼接一個完成的SQL語句,然后請求數據庫,拿到需要的數據
IEnumberable:直接把第一個命令請求數據庫,然后拿到數據,在內存當中對於后續條件進行篩選。
把IQueryable 轉換為IEnumberable :IQueryable.AsEnumberable();
EF非延遲加載:使用ToList()方法將結果立即拿到內存中(最好把命令全部拼接完之后使用ToList())
EF導航屬性的非延遲加載:Include("") 可以使導航屬性非延遲加載
EF延遲加載 優點:用時才加載數據,保證數據的有效性
EF延遲加載 缺點:每次訪問都加載一次,加重了數據庫服務器的負擔

create database MyFirstEF on primary ( name='MyFirstEF.mdf', --修改為自己電腦上SQL DB路徑 filename='E:\ProgramMSSQLServerDB\MyFirstEF.mdf', size=5mb, maxsize=100mb, filegrowth=10% ) log on ( name='MyFirstEF_log.ldf', --修改為自己電腦上SQL DB路徑 filename='E:\ProgramMSSQLServerDB\MyFirstEF_log.ldf', size=2mb, maxsize=100mb, filegrowth=5mb ) go use MyFirstEF go create table CustomerInfo ( id int identity(1,1) primary key, customerName nvarchar(100) not null, customerDate datetime ) go create table OrderInfo ( id int identity(1,1) primary key, orderName nvarchar(100), customerId int ) go alter table OrderInfo add constraint FK_OrderInfo_CustomerInfo foreign key(customerId) references CustomerInfo(id) go insert into CustomerInfo select 'aa',GETDATE() union all select 'bb',GETDATE() union all select 'cc',GETDATE() union all select 'dd',GETDATE() go insert into OrderInfo select 'bike1',2 union all select 'bike2',2 union all select 'car1',3 union all select 'car2',3 union all select 'chezi1',4 union all select 'chezi2',4 go select * from CustomerInfo go select * from OrderInfo go
>1:EF查詢默認會延遲加載
DbContext context = new MyFirstEFEntities(); //1:EF默認延遲加載,執行完下面的語句,數據庫並沒有SQL查詢語句 var rows = context.Set<CustomerInfo>().Select(c => c); //2:查詢一次數據庫 Console.WriteLine(rows.Count()); //3:第二次查詢數據庫 Console.WriteLine(rows.Count());
使用MS SQL Server Profiler(工具-->SQL Server Profiler),可以監測到上面代碼執行了兩次查詢數據庫操作
兩次查詢數據庫SQL:
SELECT [GroupBy1].[A1] AS [C1] FROM ( SELECT COUNT(1) AS [A1] FROM [dbo].[CustomerInfo] AS [Extent1] ) AS [GroupBy1]
>EF非延遲加載:ToList()方法
DbContext context = new MyFirstEFEntities(); //1:直接根據拼接SQL 查詢數據庫 var rows = context.Set<CustomerInfo>().Select(c => c).ToList(); //2:在內存中統計Count() 不會重新查詢數據庫 Console.WriteLine(rows.Count()); //3:在內存中統計Count() 不會重新查詢數據庫 Console.WriteLine(rows.Count());
使用MS SQL Server Profiler(工具-->SQL Server Profiler),可以監測到上面代碼在拼接SQL完成時,直接查詢數據庫
對應SQL:
SELECT [Extent1].[id] AS [id], [Extent1].[customerName] AS [customerName], [Extent1].[customerDate] AS [customerDate] FROM [dbo].[CustomerInfo] AS [Extent1]
>2:EF對於集合類型的導航屬性會延遲加載
DbContext context = new MyFirstEFEntities(); //1:EF默認延遲加載,執行完下面的語句,數據庫並沒有SQL查詢語句 var rows = context.Set<CustomerInfo>().Select(c => c); //2:第一次查詢數據庫,查詢CustomerInfo表 foreach (var row in rows) { //foreach時 這個會執行多次 每次@EntityKeyValue1 等於 迭代到這次的 OrderInfoId Console.WriteLine(row.OrderInfoes.Count); }
使用MS SQL Server Profiler(工具-->SQL Server Profiler),可以監測到執行到foreach時,執行CustomerInfo表格數據的查詢(即為:EF查詢默認會延遲加載)
此時對應SQL為:
SELECT [Extent1].[id] AS [id], [Extent1].[customerName] AS [customerName], [Extent1].[customerDate] AS [customerDate] FROM [dbo].[CustomerInfo] AS [Extent1]
foreach循環時 這個會執行多次 每次@EntityKeyValue1 等於 迭代到這次的 OrderInfoId,對應SQL為:
exec sp_executesql N'SELECT [Extent1].[id] AS [id], [Extent1].[orderName] AS [orderName], [Extent1].[customerId] AS [customerId] FROM [dbo].[OrderInfo] AS [Extent1] WHERE [Extent1].[customerId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1
用MS SQL Server Profiler(工具-->SQL Server Profiler),可以監測到執行到foreach時 執行了4次數據庫查詢(rows有4條CustomerInfo數據)
//也就是說 我們有多少條OrderInfo 就要執行多少次上面的查詢SQL 當然 這里使用的是exec sp_executesql 利用sp_executesql,能夠重用執行計划,這就大大提供了執行性能
>EF導航屬性的非延遲加載: Include("")方法
DbContext context = new MyFirstEFEntities(); //1:EF默認延遲加載,執行完下面的語句,數據庫並沒有SQL查詢語句 var rows = context.Set<CustomerInfo>().Include(c=>c.OrderInfoes).Select(c => c); //2:第一次查詢數據庫,查詢CustomerInfo表,以及CustomerInfo對應的所有OrderInfo數據 foreach (var row in rows) { //foreach時,不會執行數據庫查詢操作 Console.WriteLine(row.OrderInfoes.Count); }
使用MS SQL Server Profiler(工具-->SQL Server Profiler),可以監測到執行foreach時,執行CustomerInfo表格數據的查詢(EF查詢默認會延遲加載),以及CustomerInfo對應的所有OrderInfo數據(EF導航屬性的非延遲加載)
對應SQL為:
SELECT [Project1].[id] AS [id], [Project1].[customerName] AS [customerName], [Project1].[customerDate] AS [customerDate], [Project1].[C1] AS [C1], [Project1].[id1] AS [id1], [Project1].[orderName] AS [orderName], [Project1].[customerId] AS [customerId] FROM ( SELECT [Extent1].[id] AS [id], [Extent1].[customerName] AS [customerName], [Extent1].[customerDate] AS [customerDate], [Extent2].[id] AS [id1], [Extent2].[orderName] AS [orderName], [Extent2].[customerId] AS [customerId], CASE WHEN ([Extent2].[id] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1] FROM [dbo].[CustomerInfo] AS [Extent1] LEFT OUTER JOIN [dbo].[OrderInfo] AS [Extent2] ON [Extent1].[id] = [Extent2].[customerId] ) AS [Project1] ORDER BY [Project1].[id] ASC, [Project1].[C1] ASC
關閉延遲加載的方式:
1.去掉屬性里的virtual
2.context.Configuration.LazyLoadingEnabled = false;