問題
你想有效地擷取隻是用來顯示不會更新的操作的實體.另外,你想用CodeFirst的方式來實作
解決方案
一個非常常見行為,尤其是網站,就是隻是讓使用者浏覽資料.大多數情況下,使用者不會更新資料.在這種情況下,你可以通過避開上下文的緩存和修改跟蹤來提高代碼性能,你可以非常簡單地使用AsNoTracking方法來實作.
讓我們假設你一個應用程式來管理doctor(醫生)的appointments(預約),你的模型如下圖Figure 13-5.

Figure 13-5. A model for managing doctors and their appointments
首先,這個例子用EF的CodeFirst方式來實作.,在Listing 13-6建立我們的實體類, Company, Doctor, 和Appointment.
Listing 13-6. The Company, Doctor,and Appointment.Entity Object
public class Company
{
public Company()
{
Doctors = new HashSet<Doctor>();
}
public int CompanyId { get; set; }
public string Name { get; set; }
public virtual ICollection<Doctor> Doctors { get; set; }
}
public class Doctor
public Doctor()
Appointments = new HashSet<Appointment>();
public int DoctorId { get; set; }
public virtual ICollection<Appointment> Appointments { get; set; }
public virtual Company Company { get; set; }
public class Appointment
public int AppointmentId { get; set; }
public System.DateTime AppointmentDate { get; set; }
public string Patient { get; set; }
public virtual Doctor Doctor { get; set; }
}
接下來,在Listing 13-7,我們建立用CodeFirst方式時通路EF的途徑,DbContext對象
Listing 13-7. DbContext Object
public class Recipe3Context : DbContext
public Recipe3Context()
: base("Recipe3ConnectionString")
// Disable Entity Framework Model Compatibility
Database.SetInitializer<Recipe3Context>(null);
protected override void OnModelCreating(DbModelBuilder modelBuilder)
modelBuilder.Entity<Appointment>().ToTable("Chapter13.Appointment");
modelBuilder.Entity<Company>().ToTable("Chapter13.Company");
modelBuilder.Entity<Doctor>().ToTable("Chapter13.Doctor");
public DbSet<Appointment> Appointments { get; set; }
public DbSet<Company> Companies { get; set; }
public DbSet<Doctor> Doctors { get; set; }
接下來我們在項目中添加App.Config,并把下列Listing 13-8的代碼加入到ConnectionString節下
Listing 13-8. Connection String
<connectionStrings>
<add name="Recipe3ConnectionString"
connectionString="Data Source=.;
Initial Catalog=EFRecipes;
Integrated Security=True;
MultipleActiveResultSets=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
為了擷取Doctors和Companies并使他們不添加到上下文對象中,我們把AsNoTracking方法連結到擷取實體的查詢中,如Listing 13-9 那樣.
Listing 13-9. Doing a Simple Query Using the AsNoTracking Method
using (var context = new Recipe3Context())
{
var company = new Company { Name = "Paola Heart Center" };
var doc1 = new Doctor { Name = "Jill Mathers", Company = company };
var doc2 = new Doctor { Name = "Robert Stevens", Company = company };
var app1 = new Appointment
{
AppointmentDate = DateTime.Parse("3/18/2010"),
Patient = "Karen Rodgers",
Doctor = doc1
};
var app2 = new Appointment
AppointmentDate = DateTime.Parse("3/20/2010"),
Patient = "Steven Cook",
Doctor = doc2
context.Doctors.Add(doc1);
context.Doctors.Add(doc2);
context.Appointments.Add(app1);
context.Appointments.Add(app2);
context.Companies.Add(company);
context.SaveChanges();
}
using (var context = new Recipe3Context())
Console.WriteLine("Entities tracked in context for Doctors...");
// 用AsNoTracking() 方法執行查詢
context.Doctors.Include("Company").AsNoTracking().ToList();
Console.WriteLine("Number of entities loaded into context with AsNoTracking: {0}",
context.ChangeTracker.Entries().Count());//輸出:0
// 不用AsNoTracking() 方法執行查詢
context.Doctors.Include("Company").ToList();
Console.WriteLine("Number of entities loaded into context without AsNoTracking: {0}",
context.ChangeTracker.Entries().Count());//輸出:3
輸出結果如下:
Entities tracked in context for Doctors...
Number of entities loaded into context with AsNoTracking: 0
Number of entities loaded into context without AsNoTracking: 3
它是如何工作的
當我們把AsNoTracking方法連結上你的查詢,從查詢傳回的結果不會被上下文跟蹤.在我們的例子中,我們顯示地Include了Doctor的Comanpies.
預設情況下,你的查詢結果會被上下文跟蹤,這使得更新和删除更容易,但是代價是付出更多的記憶體和CPU負載.為應用程式串連更多的對象,比如在電子商務網站上浏覽産品,使用AsNoTracking選項,能節省更多的資源,使應用程式性能更高.
沒有緩存一個查詢結果,你每次都得為查詢執行個體化.通常地,使修改跟蹤可用,EF将不需要為一個上下文中已經存在的執行個體再執行個體化.
當你包含AsNoTracking選項(如我們的Listing 13-9),它隻影響目前查詢的實體.它不會影響後面的不包含AsNoTracking選項的查詢,如Listing 13-9 示範的
kid1412聲明:轉載請把此段聲明完整地置于文章頁面明顯處,并保留個人在部落格園的連結:http://www.cnblogs.com/kid1412/(可點選跳轉)。