MVC5 Entity Framework學習之實現繼承

來源:互聯網
上載者:User

標籤:entity framework   code first   migration   mvc5   inheritance   

之前你已經學習了如何處理並發異常,在本節中你將學習如何?繼承。

在物件導向的編程中,你可以使用繼承來重用代碼。接下來你將修改Instructor和Student類,讓它們派生自Person基類,該基類包含instructor和student共有的屬性如LastName。你不需要添加或修改任何WEB頁面,但是你需要修改某些代碼,這些修改會自動反映在資料庫中。

映射繼承到資料庫的選項

School 資料模型中的Instructor和Student類有幾個相同的屬性:

假設你希望通過共用Instructor和Student實體的屬性來減少冗餘的代碼,或者你希望編寫一個服務程式來格式化姓名而不必關心姓名來自instructor還是student。你可以建立一個含有這些共有屬性的Person基類,然後讓Instructor和Student繼承該基類,如所示:



在資料庫中,這種繼承結構可以有多種表現形式。你可以建立一個同時含有student和instructor資訊的Person資料庫表,該表中的某些列僅適用於instructor(HireDate),某些只適用於student(EnrollmentDate),另外的即可適用於instructor也可適用於student(LastName, FirstName)。通常情況下,你應該建立一個識別欄位來指明每一行所代表的類型,例如,識別欄位可以使用"Instructor"來表示instructors ,"Student"來表示students。


這種從單個資料庫表產生實體繼承結構的模式被稱為每個階層一個表(table-per-hierarchy)繼承。

另一種替代方法是使資料庫看起來更像是繼承結構,,例如,你可以只在Person表中包含name欄位,在Instructor 和Student表中分別包含各自的date欄位。


這種為每個實體類都建立一個資料庫表的模式被稱為每種類型一個表(table per type)繼承。

另一種選擇是將所有非抽象類別型映射到單獨的表中。類的所有屬性包括繼承的,都將映射到相應表中的列,這種模式被稱為每個具體的類一個表(Table-per-Concrete Class )繼承。如果你為Person,Student和Instructor類實現了TPC 繼承,那麼Student和Instructor表將與之前的沒有什麼不同。

在Entity Framework中TPC 和TPH繼承模式通常比TPT繼承模式具有更好地效能,因為TPT模式可能會產生複雜的串連查詢。

本節將教你如何?TPH繼承。TPH繼承是Entity Framework預設的繼承模式,所以你需要做的就是建立一個Person類,修改Instructor和Student類使其派生自Person類,將新的類添加到DbContext,並建立遷移。

建立Person類

開啟Models檔案夾,建立Person.cs類,並使用下面的方法替換

using System.ComponentModel.DataAnnotations;using System.ComponentModel.DataAnnotations.Schema;namespace ContosoUniversity.Models{    public abstract class Person    {        public int ID { get; set; }        [Required]        [StringLength(50)]        [Display(Name = "Last Name")]        public string LastName { get; set; }        [Required]        [StringLength(50, ErrorMessage = "First name cannot be longer than 50 characters.")]        [Column("FirstName")]        [Display(Name = "First Name")]        public string FirstMidName { get; set; }        [Display(Name = "Full Name")]        public string FullName        {            get            {                return LastName + ", " + FirstMidName;            }        }    }}
讓Student和Instructor類繼承Person開啟Instructor.cs,讓Instructor類繼承Person類,並刪除key 和name欄位

using System;using System.Collections.Generic;using System.ComponentModel.DataAnnotations;using System.ComponentModel.DataAnnotations.Schema;namespace ContosoUniversity.Models{    public class Instructor : Person    {        [DataType(DataType.Date)]        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]        [Display(Name = "Hire Date")]        public DateTime HireDate { get; set; }        public virtual ICollection<Course> Courses { get; set; }        public virtual OfficeAssignment OfficeAssignment { get; set; }    }}
開啟Student.cs,做同樣的修改

using System;using System.Collections.Generic;using System.ComponentModel.DataAnnotations;using System.ComponentModel.DataAnnotations.Schema;namespace ContosoUniversity.Models{    public class Student : Person    {        [DataType(DataType.Date)]        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]        [Display(Name = "Enrollment Date")]        public DateTime EnrollmentDate { get; set; }        public virtual ICollection<Enrollment> Enrollments { get; set; }    }}
將Person實體類型添加到模型中開啟 SchoolContext.cs,為Person實體類型添加DbSet 屬性

public DbSet<Person> People { get; set; }

這就是 Entity Framework配置每個階層一個表繼承所需要做的修改,稍後你會看到當資料庫被更新後,會有一個建立的Person資料表。

建立並更新遷移檔案

在 Package Manager Console (PMC)視窗,輸入如下命令

Add-Migration Inheritance
接著運行Update-Database命令,這時該命令會執行失敗,因為遷移程式不知道如何處理已經存在的資料。錯誤資訊如下

Could not drop object 'dbo.Instructor' because it is referenced by a FOREIGN KEY constraint.

開啟Migrations\<timestamp>_Inheritance.cs,修改Up方法

public override void Up(){    // Drop foreign keys and indexes that point to tables we're going to drop.    DropForeignKey("dbo.Enrollment", "StudentID", "dbo.Student");    DropIndex("dbo.Enrollment", new[] { "StudentID" });    RenameTable(name: "dbo.Instructor", newName: "Person");    AddColumn("dbo.Person", "EnrollmentDate", c => c.DateTime());    AddColumn("dbo.Person", "Discriminator", c => c.String(nullable: false, maxLength: 128, defaultValue: "Instructor"));    AlterColumn("dbo.Person", "HireDate", c => c.DateTime());    AddColumn("dbo.Person", "OldId", c => c.Int(nullable: true));    // Copy existing Student data into new Person table.    Sql("INSERT INTO dbo.Person (LastName, FirstName, HireDate, EnrollmentDate, Discriminator, OldId) SELECT LastName, FirstName, null AS HireDate, EnrollmentDate, 'Student' AS Discriminator, ID AS OldId FROM dbo.Student");    // Fix up existing relationships to match new PK's.    Sql("UPDATE dbo.Enrollment SET StudentId = (SELECT ID FROM dbo.Person WHERE OldId = Enrollment.StudentId AND Discriminator = 'Student')");    // Remove temporary key    DropColumn("dbo.Person", "OldId");    DropTable("dbo.Student");    // Re-create foreign keys and indexes pointing to new table.    AddForeignKey("dbo.Enrollment", "StudentID", "dbo.Person", "ID", cascadeDelete: true);    CreateIndex("dbo.Enrollment", "StudentID");}

上面的代碼執行了下列資料庫更新任務:

移除了Student資料庫表的外鍵約束和索引

  • 將Instructor表重新命名為Person並作如下修改來儲存Student 資料
    • 為Student 添加了可以為nullable 的EnrollmentDate
    • 添加了識別欄位來指明該列是一個student 還是instructor
    • 由於student 沒有hire date,所以設定HireDate可為nullable
    • 添加一個臨時欄位用來更新指向student 的外鍵
  • 將Student表中的資料拷貝到Person表中,這樣Student可以得到一個新的主鍵值
  • 修複了指向student的外鍵值
  • 重建了外鍵約束和索引,讓它們指向Person表

如果你已經使用了GUID而不是將integer作為主鍵類型,student 的主鍵值將不會被更改,同時上面的幾個步驟可以被省略。

再次運行update-database命令。

在生產環境中你需要對Down方法進行相應的修改以免你不得不復原至前一個資料庫版本。在本例中不需要使用Down方法。

注意:當遷移資料或更改架構時,你可能會碰到其它的錯誤,如果你遇到了遷移錯誤卻無法解決,你可以通過修改Web.config檔案中的連接字串或刪除已存在的資料庫的方法來繼續本教程,當然最簡單的方法是重新命名Web.config中的資料庫。如下所示將資料庫名稱修改為ContosoUniversity2

<add name="SchoolContext"     connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=ContosoUniversity2;Integrated Security=SSPI;"     providerName="System.Data.SqlClient" />
通過使用建立的不存在任何資料的資料庫來進行遷移,update-database應該會被成功執行。

測試

運行項目,嘗試訪問不同的頁面,一切運行正常。

開啟Server Explorer依次展開Data Connections\SchoolContext \Tables,你可以看到Student和Instructor表已經被Person表替換,開啟Person表,你可以看到該表擁有 Student 和Instructor表的所有列。


在Person表上按右鍵Show Table Data查看discriminator列


下面是新的School資料庫結構描述


部署到Windows Azure

1.在Visual Studio中,在Solution Explorer上右鍵選擇Publish


2.點擊Publish


預設瀏覽器中會自動開啟該網站

3.驗證應用程式會否工作正常

當你第一次運行項目並訪問資料庫時,Entity Framework會自動運行所有遷移中的Up方法來確保資料庫結構描述和當前資料模型一致。

原文:Implementing Inheritance with the Entity Framework 6 in an ASP.NET MVC 5 Application

歡迎轉載,請註明文章出處:http://blog.csdn.net/johnsonblog/article/details/39503915

項目源碼:https://github.com/johnsonz/MvcContosoUniversity

還大家一個健康的網路環境,從你我做起

THE END

MVC5 Entity Framework學習之實現繼承

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.