1. 程式人生 > >EF6基礎系列(九)---預先加載、延遲加載、顯示加載

EF6基礎系列(九)---預先加載、延遲加載、顯示加載

builder include nts lam teacher where fff eat ctx

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基礎系列(九)---預先加載、延遲加載、顯示加載