麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 學院 > 開發設計 > 正文

MVC系列學習(三)-EF的延遲加載

2019-11-17 02:25:57
字體:
來源:轉載
供稿:網友

MVC系列學習(三)-EF的延遲加載

1.什么叫延遲加載

字面上可以理解為,一個動作本該立即執行的動作,沒有立即執行

2.從代碼上理解

static void Main(string[] args){    //執行該語句的時候,查看sql監視器,發現并沒有生成sql語句    IEnumerable<Student> stu = dbContext.Students.Where(s => s.Id == 1).Select(s => s);    //只有當  使用的時候  ,才生成sql語句    Student student = stu.FirstOrDefault();}

只有對象被使用了,才生成sql語句

3.尋找原因,什么原因導致延遲加載

先理解兩個Where()方法:

a.集合的Where()

List<string> listStr = new List<string>(){    "A",    "BB",    "CCC"};string  bb = listStr.Where(s => s.Length == 2).Select(s => s).FirstOrDefault();

轉到Where的定義,發現 集合 中的Where方法 實際上是IEnumerable的擴展方法,該接口繼承與IEnumerable

public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> PRedicate);
public interface IEnumerable<out T> : IEnumerable

b.DbSet中的Where方法

dbContext.Students是DbSet<Student>類型,所以此處說 DbSet的中Where方法

var stu = dbContext.Students.Where(s => s.Id == 1);
public partial class SchoolEntities : DbContext{    public virtual DbSet<Student> Students { get; set; }}

image

dbContext.Students是DbSet<T>類型的,轉到DbSet<T>定義看看

此處的Where()是IQueryable的擴展方法,繼承與IQueryable

public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);
public interface IQueryable<out T> : IEnumerable<T>, IQueryable, IEnumerable
public interface IQueryable : IEnumerable

 

c.IEnumerable與IQueryable的區別

var s1 = dbContext.Students.Where(s => s.Id == 1); var s2 = s1.Where(s => s.Age > 0); var s3 = s2.Select(s => s).FirstOrDefault();

用sql監視器查看,發現總共就執行了一次sql查詢

得出結論:

1.實現EF延遲加載 的 實際上是IQueryable上的擴展方法,更具體的話是DbQuery類型來實現的 2.IEnumerable<T>將命令直接執行,第一次執行后的結果,保存到內存,不會拼接命令樹 3.IQueryable<T>將語句拼接成一個命令樹,當用到的時候,再執行 4.兩種操作都只訪問了一次數據庫

4.為什么要有延遲加載

a.無法確定 本次查詢條件 是否 已經添加結束

DbQuery<Student> s1 = dbContext.Students.Where(s => s.Id == 1).Where(s => s.Age > 0) as DbQuery<Student>;

每次添加 查詢條件的時候,都只是返回 包含所有添加條件的 DbQuery對象,只有最后使用的時候,才根據條件生成相應的sql語句

b.對于外鍵實體,按需加載

本次需要用到的兩張 具有 主外鍵關系的兩張表如下

image

image

var tea = dbContext.Teachers.Where(t => t.tId == 1);//生成sql語句,如圖 代碼一Teacher teacher = tea.FirstOrDefault();//生成sql語句,如圖 代碼二string className = teacher.TeachClass.cName;

代碼一,如下圖:

SELECT TOP (1)     [Extent1].[tId] AS [tId],     [Extent1].[tName] AS [tName],     [Extent1].[tAge] AS [tAge],     [Extent1].[tClass] AS [tClass]    FROM [dbo].[Teacher] AS [Extent1]    WHERE 1 = [Extent1].[tId]

代碼二,如下圖:

exec sp_executesql N'SELECT     [Extent1].[cId] AS [cId],     [Extent1].[cName] AS [cName]    FROM [dbo].[TeachClass] AS [Extent1]    WHERE [Extent1].[cId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1

觀察,得出結論:

1.按需加載:在第一次執行的時候,因為沒有用到外鍵屬性,所以生成sql語句的時候,不會去去查詢 TeachClass表 2.當EF需要用到外鍵屬性的時候,才會去加載 相應的表

c.按需加載的缺點:

實例代碼如下:

DbQuery<Teacher> teachers = dbContext.Teachers;StringBuilder sbTeacher=new StringBuilder(100);foreach (Teacher tea in teachers){    //每次調用 外鍵表Teachers上 的 外鍵實體時,都會去查詢數據庫    //EF有個優化,相同的外鍵實體只查一次,即TeachClass相同只查一次    sbTeacher.Append(tea.TeachClass.cName);}

生成的SQL腳本如下:

exec sp_executesql N'SELECT     [Extent1].[cId] AS [cId],     [Extent1].[cName] AS [cName]    FROM [dbo].[TeachClass] AS [Extent1]    WHERE [Extent1].[cId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1

第二次,和第三次,因為TeachClass的值相同,則只查詢了一次

exec sp_executesql N'SELECT     [Extent1].[cId] AS [cId],     [Extent1].[cName] AS [cName]    FROM [dbo].[TeachClass] AS [Extent1]    WHERE [Extent1].[cId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=2

5.連接查詢

既然EF是只有用到外鍵實體的時候,才加載相應表,那么如果我們要連接兩張表要怎么做

a.通過Include方法

DbQuery<Teacher> teachers = dbContext.Teachers.Include("TeachClass");StringBuilder sbTeacher=new StringBuilder(100);foreach (Teacher tea in teachers){    //只有第一次 查詢的使用,將數據查詢 并保存到內存中,    //接下來的操作只是在內存中讀取,并沒有讀取數據庫    sbTeacher.Append(tea.TeachClass.cName);}

查看sql語句,發現 EF為我們生成 left outer  join ,連接了兩張表

SELECT     [Extent1].[tId] AS [tId],     [Extent1].[tName] AS [tName],     [Extent1].[tAge] AS [tAge],     [Extent1].[tClass] AS [tClass],     [Extent2].[cId] AS [cId],     [Extent2].[cName] AS [cName]    FROM  [dbo].[Teacher] AS [Extent1]    LEFT OUTER JOIN [dbo].[TeachClass] AS [Extent2] ON [Extent1].[tClass] = [Extent2].[cId]

b.生成 join 的另一種方式

var teachers = dbContext.Teachers.Select(t => new {tName = t.tName, ClassName = t.TeachClass.cName}).ToList();

生成的sql語句如下

SELECT     1 AS [C1],     [Extent1].[tName] AS [tName],     [Extent2].[cName] AS [cName]    FROM  [dbo].[Teacher] AS [Extent1]    LEFT OUTER JOIN [dbo].[TeachClass] AS [Extent2] ON [Extent1].[tClass] = [Extent2].[cId]

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 国产精品69久久 | 九九热在线免费观看视频 | 欧美精品欧美极品欧美激情 | 久章草影院 | 依人九九宗合九九九 | 欧美激情综合在线 | av电影在线免费观看 | 水多视频在线观看 | 国产亚洲美女精品久久久2020 | 欧美一级片在线 | 韩国精品视频在线观看 | 免费观看又色又爽又黄的崩锅 | 久久国产精品久久久久久 | 国产精品久久久久久久久久尿 | 666sao | 在线中文字幕亚洲 | 成人精品视频网站 | 欧洲精品色 | 成人啪啪色婷婷久 | 成人国产在线看 | av影院在线播放 | 国产成人自拍av | 蜜桃视频在线观看视频 | 天天草天天爱 | 最新中文字幕在线视频 | 综合99 | 12av毛片| 日本残忍极度灌浣肠视频 | 国产免费久久久久 | 久久综合av| 国产成人自拍视频在线 | 亚洲精品一二三区 | 91精品免费在线 | 国产高潮好爽受不了了夜色 | 欧美a黄 | 日韩欧美视频一区二区三区 | 国产亚洲网 | 久久99深爱久久99精品 | 中文字幕国产亚洲 | 成人福利免费在线观看 | av成人在线播放 |