
- 實體框架教程
- 實體框架 - 首頁
- 實體框架 - 概述
- 實體框架 - 架構
- 實體框架 - 環境設定
- 實體框架 - 資料庫設定
- 實體框架 - 資料模型
- 實體框架 - DbContext
- 實體框架 - 型別
- 實體框架 - 關係
- 實體框架 - 生命週期
- 實體框架 - 程式碼優先方法
- 實體框架 - 模型優先方法
- 實體框架 - 資料庫優先方法
- 實體框架 - 開發方法
- 實體框架 - 資料庫操作
- 實體框架 - 併發
- 實體框架 - 事務
- 實體框架 - 檢視
- 實體框架 - 索引
- 實體框架 - 儲存過程
- 實體框架 - 斷開連線的實體
- 實體框架 - 表值函式
- 實體框架 - 原生SQL
- 實體框架 - 列舉支援
- 實體框架 - 非同步查詢
- 實體框架 - 持久化
- 實體框架 - 投影查詢
- 實體框架 - 命令日誌
- 實體框架 - 命令攔截
- 實體框架 - 空間資料型別
- 實體框架 - 繼承
- 實體框架 - 遷移
- 實體框架 - 急切載入
- 實體框架 - 延遲載入
- 實體框架 - 顯式載入
- 實體框架 - 驗證
- 實體框架 - 跟蹤更改
- 實體框架 - 彩色實體
- 實體框架 - 程式碼優先方法
- 實體框架 - 第一個示例
- 實體框架 - 資料註釋
- 實體框架 - Fluent API
- 實體框架 - 初始化資料庫
- 實體框架 - 程式碼優先遷移
- 實體框架 - 多個DbContext
- 實體框架 - 巢狀實體型別
- 實體框架資源
- 實體框架 - 快速指南
- 實體框架 - 有用資源
- 實體框架 - 討論
實體框架 - 第一個示例
讓我們使用類定義一個非常簡單的模型。我們只是在 Program.cs 檔案中定義它們,但在實際應用中,您會將類拆分成單獨的檔案,甚至可能是一個單獨的專案。以下是我們將使用程式碼優先方法建立的資料模型。

建立模型
使用以下程式碼為 Student 類,在 Program.cs 檔案中新增以下三個類。
public class Student { public int ID { get; set; } public string LastName { get; set; } public string FirstMidName { get; set; } public DateTime EnrollmentDate { get; set; } public virtual ICollection<Enrollment> Enrollments { get; set; } }
ID 屬性將成為與該類對應的資料庫表的主鍵列。
Enrollments 屬性是一個導航屬性。導航屬性儲存與該實體相關的其他實體。
在這種情況下,Student 實體的 Enrollments 屬性將儲存與該 Student 實體相關的所有 Enrollment 實體。
導航屬性通常定義為 virtual,以便它們可以利用某些實體框架功能,例如延遲載入。
如果導航屬性可以儲存多個實體(如多對多或一對多關係),則其型別必須是一個列表,其中可以新增、刪除和更新條目,例如 ICollection。
以下是 Course 類的實現。
public class Course { public int CourseID { get; set; } public string Title { get; set; } public int Credits { get; set; } public virtual ICollection<Enrollment> Enrollments { get; set; } }
Enrollments 屬性是一個導航屬性。一個 Course 實體可以與任意數量的 Enrollment 實體相關聯。
以下是 Enrollment 類和列舉的實現。
public enum Grade { A, B, C, D, F } public class Enrollment { public int EnrollmentID { get; set; } public int CourseID { get; set; } public int StudentID { get; set; } public Grade? Grade { get; set; } public virtual Course Course { get; set; } public virtual Student Student { get; set; } }
EnrollmentID 屬性將是主鍵。
Grade 屬性是一個列舉。Grade 型別聲明後的問號表示 Grade 屬性是可為空的。
空等級與零等級不同。空表示等級未知或尚未分配。
StudentID 和 CourseID 屬性是外部索引鍵,相應的導航屬性是 Student 和 Course。
一個 Enrollment 實體與一個 Student 和一個 Course 實體相關聯,因此該屬性只能儲存單個 Student 和 Course 實體。
建立資料庫上下文
協調給定資料模型的實體框架功能的主要類是資料庫上下文類,它允許查詢和儲存資料。您可以透過從 DbContext 類派生併為模型中的每個類公開一個型別化的 DbSet 來建立此類。
public class MyContext : DbContext { public virtual DbSet<Course> Courses { get; set; } public virtual DbSet<Enrollment> Enrollments { get; set; } public virtual DbSet<Student> Students { get; set; } }
以下是 Program.cs 檔案中的完整程式碼。
using System.ComponentModel.DataAnnotations.Schema; using System.Data.Entity; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EFCodeFirstDemo { class Program { static void Main(string[] args) {} } public enum Grade { A, B, C, D, F } public class Enrollment { public int EnrollmentID { get; set; } public int CourseID { get; set; } public int StudentID { get; set; } public Grade? Grade { get; set; } public virtual Course Course { get; set; } public virtual Student Student { get; set; } } public class Student { public int ID { get; set; } public string LastName { get; set; } public string FirstMidName { get; set; } public DateTime EnrollmentDate { get; set; } public virtual ICollection<Enrollment> Enrollments { get; set; } } public class Course { public int CourseID { get; set; } public string Title { get; set; } public int Credits { get; set; } public virtual ICollection<Enrollment> Enrollments { get; set; } } public class MyContext : DbContext { public virtual DbSet<Course> Courses { get; set; } public virtual DbSet<Enrollment> Enrollments { get; set; } public virtual DbSet<Student> Students { get; set; } } }
以上程式碼是我們開始儲存和檢索資料所需的一切。讓我們新增一些資料,然後檢索它。以下是 main 方法中的程式碼。
static void Main(string[] args) { using (var context = new MyContext()) { // Create and save a new Students Console.WriteLine("Adding new students"); var student = new Student { FirstMidName = "Alain", LastName = "Bomer", EnrollmentDate = DateTime.Parse(DateTime.Today.ToString()) }; context.Students.Add(student); var student1 = new Student { FirstMidName = "Mark", LastName = "Upston", EnrollmentDate = DateTime.Parse(DateTime.Today.ToString()) }; context.Students.Add(student1); context.SaveChanges(); // Display all Students from the database var students = (from s in context.Students orderby s.FirstMidName select s).ToList<Student>(); Console.WriteLine("Retrieve all Students from the database:"); foreach (var stdnt in students) { string name = stdnt.FirstMidName + " " + stdnt.LastName; Console.WriteLine("ID: {0}, Name: {1}", stdnt.ID, name); } Console.WriteLine("Press any key to exit..."); Console.ReadKey(); } }
執行以上程式碼時,您將收到以下輸出。
Adding new students Retrieve all Students from the database: ID: 1, Name: Alain Bomer ID: 2, Name: Mark Upston Press any key to exit...
現在想到的問題是,資料在哪裡,我們添加了一些資料然後從資料庫中檢索資料的資料庫在哪裡?按照約定,DbContext 為您建立了一個數據庫。
如果本地 SQL Express 例項可用,則 Code First 將在該例項上建立資料庫。
如果 SQL Express 不可用,則 Code First 將嘗試使用 LocalDb。
資料庫的名稱以派生上下文的完全限定名稱命名。
在我們的例子中,SQL Express 例項可用,資料庫名稱為 EFCodeFirstDemo.MyContext,如下圖所示。

這些只是預設約定,還有多種方法可以更改 Code First 使用的資料庫。
正如您在上圖中看到的,它建立了 Students、Courses 和 Enrollments 表,每個表都包含具有適當資料型別和長度的列。
列名和資料型別也與各自域類的屬性匹配。
資料庫初始化
在上面的示例中,我們已經看到 Code First 自動建立資料庫,但是如果您想更改資料庫和伺服器的名稱,讓我們看看 Code First 在初始化資料庫時如何決定資料庫名稱和伺服器。請看下圖。

您可以透過以下方式定義上下文類的基建構函式。
- 無引數
- 資料庫名稱
- 連線字串名稱
無引數
如果您如上例所示,在沒有任何引數的情況下指定上下文類的基建構函式,則實體框架將在您的本地 SQLEXPRESS 伺服器上建立一個名為 {Namespace}.{Context 類名} 的資料庫。
在上面的示例中,自動建立的資料庫名稱為 EFCodeFirstDemo.MyContext。如果您檢視名稱,您會發現 EFCodeFirstDemo 是名稱空間,MyContext 是上下文類名,如下面的程式碼所示。
public class MyContext : DbContext { public MyContext() : base() {} public virtual DbSet<Course> Courses { get; set; } public virtual DbSet<Enrollment> Enrollments { get; set; } public virtual DbSet<Student> Students { get; set; } }
資料庫名稱
如果您在上下文類的基建構函式中將資料庫名稱作為引數傳遞,則 Code First 將再次自動建立一個數據庫,但這一次名稱將是在本地 SQLEXPRESS 資料庫伺服器上的基建構函式中作為引數傳遞的名稱。
在下面的程式碼中,MyContextDB 指定為基建構函式中的引數。如果執行您的應用程式,則名為 MyContextDB 的資料庫將在您的本地 SQL 伺服器中建立。
public class MyContext : DbContext { public MyContext() : base("MyContextDB") {} public virtual DbSet<Course> Courses { get; set; } public virtual DbSet<Enrollment> Enrollments { get; set; } public virtual DbSet<Student> Students { get; set; } }
連線字串名稱
這是一種簡單的方法,可以告訴 DbContext 使用 SQL Express 或 LocalDb 之外的資料庫伺服器。您可以選擇將連線字串放在 app.config 檔案中。
如果連線字串的名稱與您的上下文名稱匹配(帶或不帶名稱空間限定),則在使用無引數建構函式時,DbContext 將找到它。
如果連線字串名稱與上下文名稱不同,則可以透過將連線字串名稱傳遞給 DbContext 建構函式來告訴 DbContext 在 Code First 模式下使用此連線。
public class MyContext : DbContext { public MyContext() : base("name = MyContextDB") {} public virtual DbSet<Course> Courses { get; set; } public virtual DbSet<Enrollment> Enrollments { get; set; } public virtual DbSet<Student> Students { get; set; } }
在上面的程式碼中,上下文類的連線字串片段指定為基建構函式中的引數。
連線字串名稱必須以“name=”開頭,否則將將其視為資料庫名稱。
此表單明確表示您希望在您的配置檔案中找到連線字串。如果找不到具有給定名稱的連線字串,則會丟擲異常。
<connectionStrings> <add name = "MyContextDB" connectionString = "Data Source =.;Initial Catalog = EFMyContextDB;Integrated Security = true" providerName = "System.Data.SqlClient"/> </connectionStrings>
app.config 中連線字串中的資料庫名稱為 **EFMyContextDB**。CodeFirst 將在本地 SQL Server 上建立一個新的 **EFMyContextDB** 資料庫或使用現有的 **EFMyContextDB** 資料庫。
域類
到目前為止,我們只是讓 EF 使用其預設約定來發現模型,但是有時我們的類不遵循約定,我們需要能夠執行進一步的配置。但是您可以透過配置域類來為 EF 提供所需的資訊來覆蓋這些約定。有兩種選項可以配置您的域類 -
- 資料註釋
- Fluent API
資料註釋
DataAnnotations 用於配置您的類,這將突出顯示最常用的配置。DataAnnotations 也被許多 .NET 應用程式(如 ASP.NET MVC)理解,這些應用程式允許這些應用程式利用相同的註釋進行客戶端驗證。
以下是學生類中使用的資料註釋。
public class Enrollment { [Key] public int EnrollmentID { get; set; } public int CourseID { get; set; } public int StudentID { get; set; } public Grade? Grade { get; set; } [ForeignKey("CourseID")] public virtual Course Course { get; set; } [ForeignKey("ID")] public virtual Student Student { get; set; } }
Fluent API
大多數模型配置可以使用簡單的資料註釋來完成。Fluent API 是一種指定模型配置的更高階方法,它涵蓋了資料註釋可以執行的所有操作,以及資料註釋無法執行的一些更高階配置。資料註釋和 Fluent API 可以一起使用。
要訪問 Fluent API,您需要覆蓋 DbContext 中的 OnModelCreating 方法。現在讓我們將學生表中的列名從 FirstMidName 重新命名為 FirstName,如下面的程式碼所示。
public class MyContext : DbContext { protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<Student>().Property(s ⇒ s.FirstMidName) .HasColumnName("FirstName"); } public virtual DbSet<Course> Courses { get; set; } public virtual DbSet<Enrollment> Enrollments { get; set; } public virtual DbSet<Student> Students { get; set; } }