[備份]EntityFramework

jackchain發表於2015-03-23

本視訊和分步演練介紹通過 Code First 開發建立新資料庫。這個方案包括建立不存在的資料庫(Code First 建立)或者空資料庫(Code First 向它新增新表)。藉助 Code First,可以使用 C# 或 VB.Net 類定義模型。可以選擇使用類的特性和屬性執行其他配置,也可以使用 Fluent API 執行其他配置。

必備條件

要完成本演練,需要安裝 Visual Studio 2010 或 Visual Studio 2012。

如果使用的是 Visual Studio 2010,還需要安裝 NuGet

 

1.建立應用程式

簡單起見,我們將構建一個使用 Code First 執行資料訪問的基本控制檯應用程式。

  • 開啟 Visual Studio
  • “檔案”->“新建”->“專案…”
  • 從左側選單中選擇“Windows”和“控制檯應用程式”
  • 輸入 CodeFirstNewDatabaseSample 作為名稱
  • 選擇“確定”

 

2.建立模型

我們使用類來定義一個非常簡單的模型。在 Program.cs 檔案中進行定義,但是實際應用程式中,可能會將類分為若干個單獨的檔案,可能作為單獨的專案。

在 Program.cs 中的程式類定義下,新增以下兩個類。

public class Blog 

    public int BlogId { get; set; } 
    public string Name { get; set; } 
 
    public virtual List<Post> Posts { get; set; } 

 
public class Post 

    public int PostId { get; set; } 
    public string Title { get; set; } 
    public string Content { get; set; } 
 
    public int BlogId { get; set; } 
    public virtual Blog Blog { get; set; } 
}

可以看到,我們將虛擬化兩個導航屬性(Blog.Posts 和 Post.Blog)。這將啟用實體框架的延遲載入功能。延遲載入意味著,嘗試訪問這些屬性的內容時,將自動從資料庫載入。

 

3.建立上下文

現在,可以定義派生上下文,用於表示資料庫的一個會話,以便我們查詢和儲存資料。我們定義一個派生自 System.Data.Entity.DbContext 的上下文,併為模型中的每個類公開一個型別化 DbSet<TEntity>。

現在,開始使用來自實體框架的型別。因此,我們需要新增 EntityFramework NuGet 程式包。

  • “專案”–>“管理 NuGet 程式包…”
    注意:如果沒有“管理 NuGet 程式包…”選項,則應安裝 最新版本的 NuGet
  • 選擇“聯機”選項卡
  • 選擇“EntityFramework”程式包
  • 單擊“安裝”

在 Program.cs 頂部,為 System.Data.Entity 新增一個 using 語句。

using System.Data.Entity;

在 Program.cs 中的 Post 類下,新增以下派生上下文。

public class BloggingContext : DbContext 

    public DbSet<Blog> Blogs { get; set; } 
    public DbSet<Post> Posts { get; set; } 
}

下面是 Program.cs 現在應包含內容的完整列表。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Data.Entity; 
 
namespace CodeFirstNewDatabaseSample 

    class Program 
    { 
        static void Main(string[] args) 
        { 
        } 
    } 
 
    public class Blog 
    { 
        public int BlogId { get; set; } 
        public string Name { get; set; } 
 
        public virtual List<Post> Posts { get; set; } 
    } 
 
    public class Post 
    { 
        public int PostId { get; set; } 
        public string Title { get; set; } 
        public string Content { get; set; } 
 
        public int BlogId { get; set; } 
        public virtual Blog Blog { get; set; } 
    } 
 
    public class BloggingContext : DbContext 
    { 
        public DbSet<Blog> Blogs { get; set; } 
        public DbSet<Post> Posts { get; set; } 
    } 
}

這是我們開始儲存和檢索資料所需的全部程式碼。顯然,後臺發生了許多事情。稍後,我們將進行了解。但是,首先讓我們看看它是如何執行的。

 

4.讀寫資料

實現 program.cs 中的 Main 方法,如下所示。這些程式碼為上下文建立一個新例項,然後使用該例項插入新部落格。之後,它使用 LINQ 查詢檢索資料庫中的所有部落格(按標題的字母順序進行排序)。

class Program 

    static void Main(string[] args) 
    { 
        using (var db = new BloggingContext()) 
        { 
            // Create and save a new Blog 
            Console.Write("Enter a name for a new Blog: "); 
            var name = Console.ReadLine(); 
 
            var blog = new Blog { Name = name }; 
            db.Blogs.Add(blog); 
            db.SaveChanges(); 
 
            // Display all Blogs from the database 
            var query = from b in db.Blogs 
                        orderby b.Name 
                        select b; 
 
            Console.WriteLine("All blogs in the database:"); 
            foreach (var item in query) 
            { 
                Console.WriteLine(item.Name); 
            } 
 
            Console.WriteLine("Press any key to exit..."); 
            Console.ReadKey(); 
        } 
    } 
}

現在,可以執行應用程式,對其進行測試。

Enter a name for a new Blog: ADO.NET 部落格
All blogs in the database:
ADO.NET 部落格
Press any key to exit...

 

我的資料在哪裡?

按照約定,DbContext 已經建立了一個資料庫。

  • 如果本地 SQL Express 例項可用(預設情況下隨 Visual Studio 2010 安裝),則 Code First 已對該例項建立了資料庫
  • 如果 SQL Express 不可用,則 Code First 將嘗試使用 LocalDb(預設情況下隨 Visual Studio 2012 安裝)
  • 資料庫以派生上下文的完全限定名命名,在我們的示例中,名稱為 CodeFirstNewDatabaseSample.BloggingContext

這些僅僅是預設約定,除此之外,還有多種方式可更改 Code First 所用的資料庫。有關更多資訊,請參見DbContext 如何發現模型和資料庫連線 主題。

 

可以在 Visual Studio 中使用伺服器資源管理器連線至此資料庫

  • “檢視”->“伺服器資源管理器”
  • 右鍵單擊“資料連線”並選擇“新增連線…”
  • 如果尚未從伺服器資源管理器連線至資料庫,則需要選擇 Microsoft SQL Server 作為資料來源
    Microsoft SQL Server 已選為資料來源
  • 連線至 LocalDb ((localdb)\v11.0) 或 SQL Express (.\SQLEXPRESS),具體取決於安裝情況
    連線至 (localdb)\v11.0 上的部落格資料庫連線至 .\SQLEXPRESS 上的部落格資料庫

 

現在,可以檢查 Code First 已經建立的架構。

顯示在伺服器資源管理器中的架構

DbContext 通過檢視我們定義的 DbSet 屬性,瞭解模型包含哪些類。隨後,它使用 Code First 約定的預設集來確定表和列的名稱,確定資料型別,查詢主鍵等。本演練稍後將介紹如何重寫這些約定。

 

5.處理模型更改

現在更改模型,當我們進行更改時,還需要更新資料庫架構。為此,我們使用一個稱為“Code First 遷移”(或簡稱“遷移”)的功能。

“遷移”是一組有序的步驟,描述如何升級(和降級)資料庫架構。這些步驟(稱為“遷移”)中的每個步驟均包含一些程式碼,用於描述要應用的更改。 

第一步是為 BloggingContext 啟用 Code First 遷移。

  • “工具”->“庫程式包管理器”->“程式包管理器控制檯”
  • 在程式包管理器控制檯中執行 Enable-Migrations 命令
  • 一個新的 Migrations 資料夾已新增至專案中,它包含兩個檔案:
    • Configuration.cs — 此檔案包含“遷移”將用來遷移 BloggingContext 的設定。在本演練中不需要進行任何更改,但是,在此處可以指定種子資料、為其他資料庫註冊提供程式、更改生成遷移的名稱空間等。
    • <時間戳>_InitialCreate.cs — 這是第一個遷移,它表示已經應用於資料庫的更改。應用更改的目的是將其從空資料庫遷移至包含部落格和文章表的資料庫。儘管我們讓 Code First 自動建立這些表,現在我們選擇“遷移”(已轉化為一次“遷移”)。Code First 還在本地資料庫中記錄:該“遷移”已經應用。檔名中的時間戳用於排序。

    現在,更改模型,向 Blog 類新增一個 Url 屬性:
public class Blog 

    public int BlogId { get; set; } 
    public string Name { get; set; } 
    public string Url { get; set; } 
 
    public virtual List<Post> Posts { get; set; } 
}
  • 在程式包管理器控制檯中執行 Add-Migration AddUrl 命令。

    Add-Migration 命令檢查自上次遷移後是否有更改,並使用所有更改搭建新遷移。我們可以為遷移指定名稱;在本例中,將此遷移稱為“AddUrl”。

    搭建的程式碼表明:我們需要向 dbo.Blogs 表新增可容納字串資料的 Url 列。如果需要,可以對搭建的程式碼進行編輯,但是,在本例中,沒有這個必要。

namespace CodeFirstNewDatabaseSample.Migrations 

    using System; 
    using System.Data.Entity.Migrations; 
     
    public partial class AddUrl : DbMigration 
    { 
        public override void Up() 
        { 
            AddColumn("dbo.Blogs", "Url", c => c.String()); 
        } 
         
        public override void Down() 
        { 
            DropColumn("dbo.Blogs", "Url"); 
        } 
    } 
}
  • 在程式包管理器控制檯中執行 Update-Database 命令。此命令將所有掛起的遷移應用於資料庫。InitialCreate 遷移已經應用,因此,這些遷移將僅應用新的 AddUrl 遷移。

    提示:在呼叫 Update-Database 命令檢視對資料庫執行的 SQL 時,可以使用 –Verbose 開關。

 

新的 Url 列已新增至資料庫中的 Blogs 表:

顯示在伺服器資源管理器中的架構 

6.資料註釋

到目前為止,EF 發現了使用其預設約定的模型。但是,有時類不遵從約定,我們需要能夠執行進一步配置。對此有兩種方法;本節將介紹資料註釋,下一節將介紹 Fluent API。

  • 向模型新增使用者類
public class User 

    public string Username { get; set; } 
    public string DisplayName { get; set; } 
}
  • 我們還需要向派生上下文新增一個集
public class BloggingContext : DbContext 

    public DbSet<Blog> Blogs { get; set; } 
    public DbSet<Post> Posts { get; set; } 
    public DbSet<User> Users { get; set; } 
}
  • 如果嘗試新增遷移,會收到錯誤訊息“EntityType‘User’未定義鍵。請為該 EntityType 定義鍵。”這是因為 EF 無法知道 Username 應為使用者的主鍵。
  • 我們將使用資料註釋,因此需要在 Program.cs 的頂部新增一個 using 語句
using System.ComponentModel.DataAnnotations;
  • 現在,註釋 Username 屬性,將它標識為主鍵
public class User 

    [Key] 
    public string Username { get; set; } 
    public string DisplayName { get; set; } 
}
  • 使用 Add-Migration AddUser 命令搭建一個遷移,將這些更改應用於資料庫
  • 執行 Update-Database 命令,將新遷移應用於資料庫

現在,新表已新增至資料庫:

顯示在伺服器資源管理器中的架構

 

EF 支援的完整註釋列表為:

 

7.Fluent API

上一節介紹瞭如何使用資料註釋來補充或重寫按約定檢測的內容。另一種模型配置方法是通過 Code First Fluent API。

大多數模型配置都可使用簡單資料註釋進行。Fluent API 是一種更高階的方法,除某些資料註釋不可能支援的更高階配置外,可以指定包含資料註釋所有功能的模型配置。資料註釋和 Fluent API 可一起使用。

要訪問 Fluent API,需要在 DbContext 中重寫 OnModelCreating 方法。假設我們需要重新命名 User.DisplayName 儲存至 display_name 的列。

  • 使用以下程式碼重寫 BloggingContext 的 OnModelCreating 方法
public class BloggingContext : DbContext 

    public DbSet<Blog> Blogs { get; set; } 
    public DbSet<Post> Posts { get; set; } 
    public DbSet<User> Users { get; set; } 
 
    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
        modelBuilder.Entity<User>() 
            .Property(u => u.DisplayName) 
            .HasColumnName("display_name"); 
    } 
}
  • 使用 Add-Migration ChangeDisplayName 命令搭建遷移,將這些更改應用於資料庫。
  • 執行 Update-Database 命令,將新遷移應用於資料庫。

 

DisplayName 列現在重新命名為 display_name:

顯示在伺服器資源管理器中的架構

摘要

本演練介紹瞭如何使用新資料庫進行 Code First 開發。我們用類定義一個模型,然後使用該模型建立一個資料庫,然後儲存和檢索資料。資料庫建立之後,我們使用 Code First 遷移將架構更改為我們發展後的模型。此外還介紹瞭如何使用資料註釋和 Fluent API 來配置模型。

相關文章