EF6基礎系列(九)---預先加載、延遲加載、顯示加載
1.預先加載:
預先加載:在對一種類型的實體進行查詢時,將相關的實體作為查詢的一部分一起加載。預先加載可以使用Include()方法實現。
1.加載一個相關實體類型
栗子:使用Include()方法從數據庫中獲取所有學生及成績級別。
導航屬性實現預先加載:
using (var ctx = new SchoolDBEntities()) { var stud1 = ctx.Students .Include("Standard") .Where(s => s.StudentName == "Bill") .FirstOrDefault<Student>(); }
lambda表達式實現預先加載:
using (var ctx = new SchoolDBEntities()) { var stud1 = ctx.Students.Include(s => s.Standard) .Where(s => s.StudentName == "Bill") .FirstOrDefault<Student>(); }
2.加載多個相關實體類型
栗子:使用Include()方法從數據庫中獲取所有學生及其成績級別和評分老師。
using (var ctx = new SchoolDBEntities()) { var stud1 = ctx.Students.Include("Standard.Teachers") .Where(s => s.StudentName == "Bill") .FirstOrDefault<Student>(); }
lambda表達式實現預先加載:
using (var ctx = new SchoolDBEntities()) {var stud1 = ctx.Students.Include(s => s.Standard.Teachers) .Where(s => s.StudentName == "Bill") .FirstOrDefault<Student>(); }
2.延遲加載
1.概念
延遲加載顧名思義就是不立即加載,而是在我們訪問的時候才加載,這和預先加載剛好相反。
一個栗子:查詢Student的StudentAddress
using (var ctx = new SchoolDBEntities()) { //這裏只加載student實體 IList<Student> studList = ctx.Students.ToList<Student>(); Student std = studList[0]; //只加載特定student的住址(通過一個單獨的sql進行實現的) StudentAddress add = std.StudentAddress; }
2.禁用延遲加載
我們可以禁用特定實體或者特定context的延遲加載。去掉實體導航屬性的virtual,實體就不能進行延遲加載了。也可以通過context的cofiguration實現禁用該context下所有實體的延遲加載,代碼如下:
public partial class SchoolDBEntities : DbContext { public SchoolDBEntities(): base("name=SchoolDBEntities") { //SchoolDBEntities的所有實體都禁用延遲加載 this.Configuration.LazyLoadingEnabled = false; } //如果去掉virtual那麽Students禁用延遲加載 public virtual DbSet<Student> Students { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder){} }
3.延遲加載前提
如果要實現延遲加載,必須滿足下邊三個條件,缺一不可
1.context.Configuration.ProxyCreationEnabled應為true。 2.context.Configuration.LazyLoadingEnabled應為true。 3.導航屬性應定義為public virtual xxx,如果屬性未定義為virtual,則Context不會進行延遲加載。
3.顯示加載
1.Load方法
即使禁用了延遲加載(在EF 6中),仍然可能延遲加載相關實體,這時可以使用Load()方法顯式加載相關實體。
一個栗子:
using (var context = new SchoolContext()) { var student = context.Students .Where(s => s.FirstName == "Bill") .FirstOrDefault<Student>(); context.Entry(student).Reference(s => s.StudentAddress).Load(); // loads StudentAddress context.Entry(student).Collection(s => s.StudentCourses).Load(); // loads Courses collection }
在上面的栗子中, context.Entry(student).Reference(s => s.StudentAddress).Load() 會加載StudentAddress實體。Reference()方法用於獲取指定實體導航屬性的對象,Load()方法顯式加載。
同樣的方式, context.Entry(student).Collection(s => s.Courses).Load() Collection()加載student的集合導航屬性Courses,Load()方法顯示加載。
2.Query方法
有時候我們想對查詢的結果在加載前進行過濾,Query()方法就可以排上用場了。
一個栗子:查詢名字為bill的學生的課程集合中數學課。
using (var context = new SchoolContext()) { var student = context.Students .Where(s => s.FirstName == "Bill") .FirstOrDefault<Student>(); context.Entry(student) .Collection(s => s.StudentCourses) .Query()//這裏不加載,下面對這一步的結果過濾 .Where(sc => sc.CourseName == "Maths") .FirstOrDefault(); }
在上邊栗子中 .Collection(s => s.StudentCourses).Query() 不加載結果集,我們可以把Query()方法的結果看作是一個中間結果,可以對中間結果做進一步過濾。
EF6基礎系列(九)---預先加載、延遲加載、顯示加載