Contoso 大學 - 1 - 為 ASP.NET MVC 應用程序創建 EF 數據模型


原文地址:Creating an Entity Framework Data Model for an ASP.NET MVC Application (1 of 10)

 

Contoso 大學 Web 示例應用演示了如何使用 EF 技術創建 ASP.NET MVC 應用。示例中的 Contoso 大學是虛構的。應用包括了類似學生注冊、課程創建以及教師分配等功能。

這個系列教程展示了創建 Contoso 大學應用的步驟。你可以 下載完整 的程序,或者按照教程一步一步創建它,這個教程中使用 C# 進行演示,下載的代碼中同時包含 C# 和 VB 實現。如果你有與這個教程沒有直接相關的問題,可以張貼到 ASP.NET Entity Framework forum  或者 Entity Framework and LINQ to Entities forum.

這個教程假設你知道如何使用 Visual Studio 來開發 ASP.NET MVC 程序,如果不是這樣,basic ASP.NET MVC Tutorial 是不錯的起點。如果你以前使用 Web Form 開發,可以先看看 Getting Started with the Entity FrameworkContinuing with the Entity Framework  教程。

在開始之前,確信下列軟件已經安裝在你的計算機上:

Contoso 大學 Web 應用

在這個教程中你將創建的應用是一個簡單的大學網站。

用戶可以查看和更新學生、課程、以及教師信息。你將會創建的一些界面如下所示:

由於教程主要關注於如何使用 EF ,所以界面的風格與內置模板的風格保持一致。

EF 開發方法

如下圖所示,存在三種方式來使用 EF:數據庫優先,模型優先和代碼優先。

數據庫優先

如果你已經創建了數據庫,EF 可以自動生成創建數據模型,包含關聯到數據庫中表和字段的類和屬性。關於數據庫結構的信息(存儲架構)、數據模型(概念模型)、它們之間的映射被存儲在擴展名為 .edmx 的 XML 文件中。Visual Studio 提供了 EF 設計器,這是一個圖形化的設計器,可以用來顯示和編輯 .edmx 文件。Getting Started With the Entity Framework  和 Continuing With the Entity Framework 介紹了使用數據庫優先的開發。

模型優先

如果你還沒有數據庫,你可以在 Visual Stdio 中使用 EF 的設計器通過創建模型來開始。當模型創建之后,設計器可以生成 DDL 語句來創建相應的數據庫。這個方法也使用 .edmx 文件來存儲模型以及映射信息。 What's New in the Entity Framework 4 介紹了模型優先的開發。

代碼優先

不管你是否已經有數據庫,你仍然可以編寫自己的類和數據關聯到數據表和字段,使用 EF 而不需要 .edmx 文件。所有有時候這種方法又被稱為 Code Onle。當然經典的名稱為 Code First。在數據庫的存儲架構到概念模型之間的映射通過約定以及特定的映射 API 完成。如果你還沒有數據庫,EF 可以自動為你創建它,在模型改變的時候,先刪除掉然后重新創建,這個教程使用代碼優先的方式進行開發。

使用代碼優先的方式進行數據庫訪問的 API 基於 DbContext 類。這也同樣可以用於數據庫優先或者模型優先的開發流程。 更多詳細的內容,可以看 When is Code First not code first?

POCO (簡單的老的 CLR 對象)

默認情況下,當你使用數據庫優先或者模型優先開發方法的時候,你的數據模型對象需要派生自 EntityObject 類,通過它提供 EF 功能。這意味着這些類不能是 持久性無感知(persistence ignorant ) 的,所以不能符合領域驅動開發的要求。所有的 EF 開發方法都支持使用 POCO 類,由於不需要派生自 EntityObject ,所以,這樣的類是持久性無感知的。在這個教程中,我們將會使用 POCO 類。

創建 MVC 應用

在開始之前,確信下列軟件已經安裝在你的計算機上:

打開 Visual Studio,使用 ASP.NET MVC 3 Web Application 創建名為 ContosoUniversity 的應用。

在新 ASP.NET MVC3 項目對話框中,選中 Internet 應用程序模板和 Razor 視圖引擎,清除創建單元測試項目復選框,然后選擇確定。

設置站點的風格

通過一些簡單的修改來設置站點的菜單,布局和主頁。

為了設置 Contoso 大學的菜單,在 Views\Share\_Layout.cshtml 文件,替換現存的 h1 標題和菜單鏈接,如下所示:

在 Views\Home\Index.cshtml 文件中,刪除位於 h2 標題之下的所有內容。

在 Controllers\HomeController.cs 文件中,將 "歡迎使用 ASP.NET MVC!" 替換為 "歡迎來到 Contoso University!"

在 Content\Site.css 文件中,做如下的修改,使得菜單放置到左邊。

在 #main 定義中,增加 clear: both ,如下所示:

在 nav 和 #menucontainer 定義中,增加 clear: both; float: left; ,如下所示。

運行程序,應該看到帶有主菜單的主頁。

創建數據模型

下一步,需要創建 Contoso 大學應用的第一組實體類,從下面的三個實體開始。

在學生 (Student) 實體和 注冊 (Enrollment) 實體之間存在一對多的關聯, 在課程 (Course) 和 注冊 (Enrollment) 之間也存在一對多的關聯。或者說,一個學生可以注冊許多課程,一個課程可以被許多學生注冊。

下面的時間,你需要為每個實體創建相應的類。

注意:如果你在創建完成所有這些類的時候編譯程序,將會看到編譯錯誤。

學生實體

在 Models 文件夾中,創建 Student.cs 類,將原有的代碼使用下面的代碼替換掉。

using System;
using System.Collections.Generic;
namespace ContosoUniversity.Models
{
public class Student {
public int StudentID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public DateTime EnrollmentDate { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
}
}

StudentID 屬性將會映射到數據庫中關聯到這個類的表的主鍵,默認情況下,EF 將屬性名為 ID 或者 類名ID 的屬性作為主鍵。

Enrollments 屬性是導航屬性,導航屬性用來導航到這個實體關聯的其他實體。Student 類的 Enrollments 屬性用來持有這個學生關聯的所有注冊實體。或者說,如果在數據庫中,一個學生行有兩個關聯的注冊行(通過 StudentId 這個外鍵關聯到學生表),學生實體的注冊屬性將會包含包含兩個注冊實體。

導航屬性典型地被定義為虛擬的 virtual,以便通過 EF 名為延遲加載的功能來獲得好處,(延遲加載將在后面進行說明),如果導航屬性可以持有多個實體,(在多對多情況下,或者一對多情況下),類型必須為 ICollection。

注冊實體

在 Models 文件夾中,創建 Enrollment.cs 文件,將原有的代碼替換為如下代碼:

using System;
using System.Collections.Generic;
namespace ContosoUniversity.Models
{
public class Enrollment
{
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
public decimal? Grade { get; set; }
public virtual Course Course { get; set; }
public virtual Student Student { get; set; }
}
}

在 decimal 類型后面的 ? 表示成績 (Grade) 是可空的。成績是空的不同於 0,空意味着還沒有成績,0 意味着成績為 0。

StudentID 屬性是外鍵,關聯的導航屬性為 Student。一個 Enrollment 關聯一個 Student,所以這個屬性只能持有一個 Student 實體 (不像 Student.Enrollments 導航屬性)。

CourseID 屬性也是外鍵,關聯的導航屬性為 Course,一個 Enrollment 關聯一個 Course 實體。

課程實體

在 Models 文件夾中,創建 Course.cs 代碼文件,使用下面的代碼替換原有的代碼。

using System;
using System.Collections.Generic;
namespace ContosoUniversity.Models
{
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 實體可以關聯多個注冊實體。

創建數據庫上下文

在 EF 中,主要的協調數據訪問功能的類是數據庫上下文類。你需要創建派生自 System.Data.Entity.DbContext 的類,在你的代碼中指定數據模型中包含的實體。你可以定制某些 EF 的行為。在這個項目中,這個類的名字為 SchoolContext。

創建一個名為 DAL 的文件夾,在這個文件夾中創建名為 SchoolContext 的類,使用下面的代碼替換原有的代碼。

using System;
using System.Collections.Generic;
using System.Data.Entity;
using ContosoUniversity.Models;
using System.Data.Entity.ModelConfiguration.Conventions;
namespace ContosoUniversity.Models
{
public class SchoolContext
: DbContext
{
public DbSet<Student> Students { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Course> Courses { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
}

這段代碼使用 DbSet 類型的屬性定義每一個實體集。在 EF 術語中,一個實體集典型地關聯到一個數據庫中的表,一個實體關聯到表中的一行。

在 OnModelCreating 方法中的代碼防止數據庫中的表名被多元化。如果沒有這樣處理的話,生成的表將會被命名為 Students,Courses 和 Enrollments。現在,表名將會被命名為 Student,Course 和 Enrollment。開發者可以決定表名是否被多元化。這個教程使用單數模式,但是重要的是你可以這行代碼來選擇喜歡的模式。

(這個類位於 Models 命名空間,有些時候 EF 假定實體類和上下文類在相同的命名空間中)

設置連接字符串

你還沒有創建數據庫連接串,如果你不去創建它,EF 將會自動為你創建一個 SQL Server Express 的數據庫。這個教程中,你將要使用 SQL Server Compact,所以,需要你來創建一個數據庫連接串。

打開項目的 web.config 文件,在 connectionStrings 配置中增加一個新的數據庫連接串,如下所示,(確信是項目根目錄中的 web.config ,注意在 Views 中還有一個,你不需要更新它)

<add name="SchoolContext" connectionString="Data Source=|DataDirectory|School.sdf" providerName="System.Data.SqlServerCe.4.0"/>

默認情況下,EF 查找與數據庫上下文類同名的數據庫連接串。你現在添加的鏈接串將會導致在 App_Data 文件夾中創建名為 School.sdf 的 SQL Server Compact 數據庫文件。

使用測試數據初始化數據庫

EF 可以在應用啟動的時候,自動創建 (或者先刪除再重新創建)數據庫。你可以指定是在每次運行程序的時候還是在模型與數據庫不一致的時候進行這個工作。你還可以指定一個 EF 在創建數據庫之后可以自動調用的方法,以便填充測試數據。在這里,我們指定當模型與數據庫不一致的時候刪除然后重新創建數據庫。

在 DAL 文件夾中,創建一個名為 SchoolInitializer.cs 的類,使用下面的代碼替換原有的代碼,使得在創建數據庫之后為新的數據庫填充測試數據。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
using ContosoUniversity.Models;
namespace ContosoUniversity.DAL
{
public class SchoolInitializer
: DropCreateDatabaseIfModelChanges<SchoolContext>
{
protected override void Seed(SchoolContext context)
{
var students = new List<Student>
{
new Student { FirstMidName = "Carson", LastName = "Alexander", EnrollmentDate = DateTime.Parse("2005-09-01") },
new Student { FirstMidName = "Meredith", LastName = "Alonso", EnrollmentDate = DateTime.Parse("2002-09-01") },
new Student { FirstMidName = "Arturo", LastName = "Anand", EnrollmentDate = DateTime.Parse("2003-09-01") },
new Student { FirstMidName = "Gytis", LastName = "Barzdukas", EnrollmentDate = DateTime.Parse("2002-09-01") },
new Student { FirstMidName = "Yan", LastName = "Li", EnrollmentDate = DateTime.Parse("2002-09-01") },
new Student { FirstMidName = "Peggy", LastName = "Justice", EnrollmentDate = DateTime.Parse("2001-09-01") },
new Student { FirstMidName = "Laura", LastName = "Norman", EnrollmentDate = DateTime.Parse("2003-09-01") },
new Student { FirstMidName = "Nino", LastName = "Olivetto", EnrollmentDate = DateTime.Parse("2005-09-01") }
};
students.ForEach(s => context.Students.Add(s));
context.SaveChanges();

var courses = new List<Course>
{
new Course { Title = "Chemistry", Credits = 3, },
new Course { Title = "Microeconomics", Credits = 3, },
new Course { Title = "Macroeconomics", Credits = 3, },
new Course { Title = "Calculus", Credits = 4, },
new Course { Title = "Trigonometry", Credits = 4, },
new Course { Title = "Composition", Credits = 3, },
new Course { Title = "Literature", Credits = 4, }
};
courses.ForEach(s => context.Courses.Add(s));
context.SaveChanges();

var enrollments = new List<Enrollment>
{
new Enrollment { StudentID = 1, CourseID = 1, Grade = 1 },
new Enrollment { StudentID = 1, CourseID = 2, Grade = 3 },
new Enrollment { StudentID = 1, CourseID = 3, Grade = 1 },
new Enrollment { StudentID = 2, CourseID = 4, Grade = 2 },
new Enrollment { StudentID = 2, CourseID = 5, Grade = 4 },
new Enrollment { StudentID = 2, CourseID = 6, Grade = 4 },
new Enrollment { StudentID = 3, CourseID = 1 },
new Enrollment { StudentID = 4, CourseID = 1, },
new Enrollment { StudentID = 4, CourseID = 2, Grade = 4 },
new Enrollment { StudentID = 5, CourseID = 3, Grade = 3 },
new Enrollment { StudentID = 6, CourseID = 4 },
new Enrollment { StudentID = 7, CourseID = 5, Grade = 2 },
};
enrollments.ForEach(s => context.Enrollments.Add(s));
context.SaveChanges();
}
}
}

Seed 方法將數據庫上下文對象作為參數,方法中的代碼使用這個對象為數據庫添加實體。對於每種實體類型,代碼創建實體集,將它們添加到相應的 DbSet 屬性中,然后在數據庫中保存修改。並不需要在每一組實體之后都要調用 SaveChanges 方法,這里這么做,是當寫入數據到數據庫中出現問題的時候,可以比較方便地找到問題。

在 Global.asax.cs 中做如下的修改,使得在應用開始的時候調用初始化代碼。

增加 using 語句

using System.Data.Entity;
using ContosoUniversity.Models;
using ContosoUniversity.DAL;

在 Application_Start 方法中,調用 EF 方法,以便運行初始化器。

Database.SetInitializer<SchoolContext>(new SchoolInitializer());

現在應用已經設置完成,當程序開始運行的時候,EF 將會比較數據庫,如果不同的話,應用會刪除然后重建數據庫。

注意:當應用部署到生產環境的時候,必須刪除這段代碼。

現在,你可以創建一個頁面來顯示數據了,請求數據的處理將會自動觸發創建數據庫。你需要通過創建新的控制器開始。但在開始這些操作之前,先編譯項目,使得對於 MVC 的腳手架來說,模型和上下文對象已經存在。

創建學生控制器

為了創建 Student 控制器,在解決方案管理其中的 Controllers 文件夾上右擊,選擇添加,然后點擊控制器,在添加控制器的對話框中,做如下的選擇,然后添加

控制器的名稱為:StudentController。

模板為:包含讀/寫操作和視圖的控制器 (使用 Entity Framework)

模型類:Student (ContosoUniversity.Models) (如果沒有找到,重新編譯項目之后再試一下)

數據上下文類:SchoolContext (ContosoUniversity.Models)

視圖:Razor(CSHTML)

打開 Controllers\StudentController.cs 文件,你會看到一個類級的變量,賦予了一個數據上下文實例。

private SchoolContext db = new SchoolContext();

名為 Index 的 Action 方法通過數據上下文對象的 Students 屬性獲取一個學生的列表.

public ViewResult Index()
{
return View(db.Students.ToList());
}

腳手架還為我們創建了一系列的 Student 視圖,為了定制 Index 視圖,打開 Views\Student\Index.cshtml ,使用下面的代碼替換原有的內容。

@model IEnumerable<ContosoUniversity.Models.Student>
@{ ViewBag.Title = "Students";}
<h2>
Students</h2>
<p>
@Html.ActionLink("Create New", "Create")</p>
<table>
<tr>
<th>
</th>
<th>
Last Name
</th>
<th>
First Name
</th>
<th>
Enrollment Date
</th>
</tr>
@foreach (var item in Model)
{ <tr>
<td>
@Html.ActionLink("Edit", "Edit", new { id = item.StudentID }) | @Html.ActionLink("Details", "Details", new { id = item.StudentID })
| @Html.ActionLink("Delete", "Delete", new { id = item.StudentID })
</td>
<td>
@Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
@Html.DisplayFor(modelItem => item.FirstMidName)
</td>
<td>
@Html.DisplayFor(modelItem => item.EnrollmentDate)
</td>
</tr>}</table>

現在,運行程序,點擊 Student 選項卡,你就可以看到學生的列表。

關掉瀏覽器,在解決方案管理器中,選擇 ContosoUniversion 項目,點擊 顯示所有文件,如果已經在這個模式,點擊刷新,然后展開 App_Data 文件夾,查看 School.sdf 文件。

雙擊 School.sdf 文件,打開服務器資源管理器,展開 Tables ,查看在數據庫中已經創建的表。

注意:如果在雙擊 School.sdf 的時候得到一個錯誤提示,確信你已經安裝了 Visual Studio 2010 SP1 Tools for SQL Server Compact 4.0.

對於每一種實體對應一張表,外加一個附加表 EdmMetadata,這個表用於檢測數據庫與模型的同步。

右擊一張表,然后選擇 Show Table Data,查看在初始化器重添加的數據。

在完成查看之后,注意關閉連接。(如果不關閉連接的話,下次運行程序會遇到一個錯誤)

實體框架使用約定來最小化開發工作,注意下面的幾點:

  • 多元化實體名作為數據庫中的表名
  • 實體屬性用於表中的列名
  • 實體中名為 ID 或者類名加上 ID 作為表的主鍵
  • EF 使用數據上下文的名字作為數據庫連接串的名字


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM