MVC5+EF6--1 建立Entity Framework數據模型

近期學習MVC5+EF6,找到了Microsoft的原文,一個很是棒的系列,Getting Started with Entity Framework 6 Code First using MVC 5,網址:http://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net-mvc-application。css

    這個系列的原文,能夠上面網址找到。我也從網上找到了相關的譯文。申明,這些譯文,我不是原創,而是從網上找來的,爲避免下次還要網上查詢,現將這些譯文整理放在上面。之後找時間將原文地址附上html

MVC5+EF6--1  建立Entity Framework數據模型jquery

網址:web

Contoso University示例網站演示如何使用Entity Framework 5建立ASP.NET MVC 4應用程序。sql

Entity Framework有三種處理數據的方式: Database First, Model First, and Code First. 本指南使用代碼優先。其它方式請查詢資料。數據庫

示例程序是爲Contoso University創建一個網站。功能包括:學生管理、課程建立、教師分配。 本系列指南逐步講述如何實現這一網站程序。express

本示例程序基於 ASP.NET MVC.若是使用 ASP.NET Web Forms model, 請查看 Model Binding and Web Forms系列指南和 ASP.NET Data Access Content Map.編程

若有問題,可在這些討論區提問: ASP.NET Entity Framework forum, the Entity Framework and LINQ to Entities forum, or StackOverflow.com.mvc


(此指南的舊版本請查看 the EF 4.1 / MVC 3 e-book.) app

Contoso University 應用程序

本指南將建立一個簡單的大學網站.

用戶可查看或更新學生、課程、教師的信息,如下是相關截圖:

                         

 

UI風格延續了默認模板的風格,以便更多關注於如何使用Entity Framework。

需求

使用 Visual Studio 2012 or Visual Studio 2012 Express for Web, 可從如下連接獲取相關需求軟件:

Windows Azure SDK for Visual Studio 2012

若是已經安裝 Visual Studio,此連接將只安裝缺乏的組件.若是沒有Visual Studio, 將安裝Visual Studio 2012 Express for Web. 你也可以使用Visual Studio 2013,但一些步驟和截圖有所不一樣.

若使用 Visual Studio 2010,須要安裝MVC 4 和 SQL Server LocalDB.

建立MVC Web程序

建立程序以下:

 

選擇 Internet Application template.

選擇 Razor

點擊OK.

 

設置網站風格

菜單、佈局有少量變更.

打開Views\Shared\_Layout.cshtml, 修改以下:黃色爲修改後內容.

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title>@ViewBag.Title - Contoso University</title>
        <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
        <meta name="viewport" content="width=device-width" />
        @Styles.Render("~/Content/css")
        @Scripts.Render("~/bundles/modernizr")
    </head>
    <body>
        <header>
            <div class="content-wrapper">
                <div class="float-left">
                    <p class="site-title">@Html.ActionLink("Contoso University", "Index", "Home")</p>
                </div>
                <div class="float-right">
                    <section id="login">
                        @Html.Partial("_LoginPartial")
                    </section>
                    <nav>
                        <ul id="menu">
                            <li>@Html.ActionLink("Home", "Index", "Home")</li>
                            <li>@Html.ActionLink("About", "About", "Home")</li>
                            <li>@Html.ActionLink("Students", "Index", "Student")</li>
                            <li>@Html.ActionLink("Courses", "Index", "Course")</li>
                            <li>@Html.ActionLink("Instructors", "Index", "Instructor")</li>
                            <li>@Html.ActionLink("Departments", "Index", "Department")</li>
                        </ul>
                    </nav>
                </div>
            </div>
        </header>
        <div id="body">
            @RenderSection("featured", required: false)
            <section class="content-wrapper main-content clear-fix">
                @RenderBody()
            </section>
        </div>
        <footer>
            <div class="content-wrapper">
                <div class="float-left">
                    <p>&copy; @DateTime.Now.Year - Contoso University</p>
                </div>
            </div>
        </footer>
 
        @Scripts.Render("~/bundles/jquery")
        @RenderSection("scripts", required: false)
    </body>
</html>

上面作了兩點改變:

  • 把 "My ASP.NET MVC Application" 和"your logo here" 替換爲"Contoso University".
  • 添加一些後面用到的超連接

在Views\Home\Index.cshtml, 替換爲以下代碼:

@{
    ViewBag.Title = "Home Page";
}
@section featured {
    <section class="featured">
        <div class="content-wrapper">
            <hgroup class="title">
                <h1>@ViewBag.Title.</h1>
                <h2>@ViewBag.Message</h2>
            </hgroup>
        </div>
    </section>
}

在 Controllers\HomeController.cs, 把 ViewBag.Message 值替換爲 "Welcome to Contoso University!":

public ActionResult Index()
{
    ViewBag.Message = "Welcome to Contoso University";
 
    return View();
}

 CTRL+F5 運行,界面以下.

 

建立數據模型

先建立以下三個數據模型:

 

Student and Enrollment 實體是一對多關係,, Course and Enrollment 實體也是一對多關係. 也就是說一個學生能夠註冊多門課程,一門課程容許多位學生註冊。

爲每一個實體建立對應的類:

注意:在完成全部實體以前嘗試編譯,將致使編譯失敗.

Student Entity

 

在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 屬性將成爲數據表的主鍵列。默認Entity Framework將名爲ID或者類名ID的屬性設爲主鍵。

 Enrollments 是一個導航屬性。導航屬性記錄和本實體相關的其它實體。在本例中,Enrollments 屬性記錄和 Student 屬性相關的Enrollment。.若是數據庫中某Student記錄和兩條Enrollment記錄 相關。(這兩條記錄的 StudentID 外鍵值等於該Student的StudentID) ,那麼Student 實體的 Enrollments 導航屬性將包含這兩個 Enrollment 實體.

Navigation properties 常定義爲virtual 以便發揮Entity Framework的功能,如 lazy loading. (在 Reading Related Data 部分將詳細講述延遲加載).

若是navigation property 包含多記錄 (如 many-to-many or one-to-many 關係), 類型最好是列表類型,如 ICollection.

The Enrollment Entity

 

在Models文件夾, 建立 Enrollment.cs,代碼以下:

namespace ContosoUniversity.Models
{
    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; }
    }
}

 Grade類型 後面的問號表示Grade 屬性是 nullable.

StudentID property 是外鍵, 相應的導航屬性是 Student.一個 Enrollment實體和一個 Student實體相關, 

 CourseID property是外鍵, 相應的導航屬性是 Course

The Course Entity

 

在Models文件夾, 建立Course.cs, 代碼以下:

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
 
namespace ContosoUniversity.Models
{
    public class Course
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        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實體.

下一節再對 [DatabaseGenerated(DatabaseGeneratedOption.None)] 特性進行講解。 簡而言之,此特性代表主鍵由你賦值而非數據庫自動生成。 

建立Database Context

將 Entity Framework 功能和給定數據模型相關聯的類是 database context class. 此類繼承自 System.Data.Entity.DbContext class.代碼代表數據模型包含了哪些實體類型.本項目中數據上下文類名爲 SchoolContext.

建立 DAL文件夾 (for Data Access Layer). 在此文件夾建立SchoolContext.cs,代碼以下:

using ContosoUniversity.Models;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;
 
namespace ContosoUniversity.DAL
{
    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 屬性。. 在Entity Framework,實體集合對應數據表,一個實體對應表中的一條記錄。.

modelBuilder.Conventions.Remove 語句阻止表名使用實體的複數形式,若是沒有此語句,則生成的數據表分別是  StudentsCourses, andEnrollments. 使用此語句,表名將和實體名同樣 StudentCourse, and Enrollment. 這和編程風格相關,至因而否使用複數取決於你本身。

SQL Server Express LocalDB

LocalDB 是一個輕量級的SQL Server。這裏不作翻譯介紹。

打開根目錄下的 Web.config 文件,在 connectionStrings 處添加鏈接字符串以下,(注意,若是沒有localdb,而使用SQL Server或者Express版本,請修改鏈接字符串)

 <add name="SchoolContext" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=ContosoUniversity;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\ContosoUniversity.mdf" providerName="System.Data.SqlClient" />

默認Entity Framework尋找和數據上下文類同名的鏈接字符串 (SchoolContext for this project). 更多鏈接字符串信息,請查看 SQL Server Connection Strings for ASP.NET Web Applications.

也可不添加鏈接字符串,由程序自動生成。但會致使數據庫文件沒有放在程序的 App_data文件夾下,更多信息請查看  Code First to a New Database.

 connectionStrings 集合默認包含一個名爲 DefaultConnection的鏈接字符串,是用來鏈接  membership database. 這裏不會用到。兩條鏈接字符串惟一不一樣之處是數據庫名字不一樣

設置並執行 Code First Migration

在程序初期,數據模型常常發生變更,每次變更就會致使和數據庫不一致。可將Entity Framework配置爲變更後自動重建數據庫。但在程序使用以後若是發生變更,更但願是更新數據庫而非重建(重建致使數據丟失)。 Migrations 功能使得代碼優先方式下更新數據庫。若是但願重建可以使用DropCreateDatabaseIfModelChanges實現每次變更後重建數據庫。.  本例中咱們直接使用Migration方法,更多信息請查看 Code First Migrations.

啓用Code First Migrations

  1. 工具菜單,選擇Library Package Manager ,Package Manager Console.

 

  1.  PM> 提示符下輸入以下命令:
enable-migrations -contexttypename SchoolContext

 

命令將建立 Migrations文件夾,並在文件夾下建立Configuration.cs.

 

Configuration 類包含 Seed 方法,數據庫建立或更新後將調用此方法。

internal sealed class Configuration : DbMigrationsConfiguration<ContosoUniversity.Models.SchoolContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
    }
 
    protected override void Seed(ContosoUniversity.Models.SchoolContext context)
    {
        //  This method will be called after migrating to the latest version.
 
        //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
        //  to avoid creating duplicate seed data. E.g.
        //
        //    context.People.AddOrUpdate(
        //      p => p.FullName,
        //      new Person { FullName = "Andrew Peters" },
        //      new Person { FullName = "Brice Lambson" },
        //      new Person { FullName = "Rowan Miller" }
        //    );
        //
    }
}

  Seed 方法使得可設置自動插入到數據庫中的數據

設置Seed方法

爲了便於測試,咱們在Seed中添加一些數據

  1. 替換 Configuration.cs內容以下: 

2.  namespace ContosoUniversity.Migrations
3.  {
4.     using System;
5.     using System.Collections.Generic;
6.     using System.Data.Entity.Migrations;
7.     using System.Linq;
8.     using ContosoUniversity.Models;
9.   
10.           internal sealed class Configuration : DbMigrationsConfiguration<ContosoUniversity.DAL.SchoolContext>
11.           {
12.              public Configuration()
13.              {
14.                 AutomaticMigrationsEnabled = false;
15.              }
16.         
17.              protected override void Seed(ContosoUniversity.DAL.SchoolContext context)
18.              {
19.                 var students = new List<Student>
20.                    {
21.                        new Student { FirstMidName = "Carson",   LastName = "Alexander", 
22.                            EnrollmentDate = DateTime.Parse("2010-09-01") },
23.                        new Student { FirstMidName = "Meredith", LastName = "Alonso",    
24.                            EnrollmentDate = DateTime.Parse("2012-09-01") },
25.                        new Student { FirstMidName = "Arturo",   LastName = "Anand",     
26.                            EnrollmentDate = DateTime.Parse("2013-09-01") },
27.                        new Student { FirstMidName = "Gytis",    LastName = "Barzdukas", 
28.                            EnrollmentDate = DateTime.Parse("2012-09-01") },
29.                        new Student { FirstMidName = "Yan",      LastName = "Li",        
30.                            EnrollmentDate = DateTime.Parse("2012-09-01") },
31.                        new Student { FirstMidName = "Peggy",    LastName = "Justice",   
32.                            EnrollmentDate = DateTime.Parse("2011-09-01") },
33.                        new Student { FirstMidName = "Laura",    LastName = "Norman",    
34.                            EnrollmentDate = DateTime.Parse("2013-09-01") },
35.                        new Student { FirstMidName = "Nino",     LastName = "Olivetto",  
36.                            EnrollmentDate = DateTime.Parse("2005-08-11") }
37.                    };
38.                 students.ForEach(s => context.Students.AddOrUpdate(p => p.LastName, s));
39.                 context.SaveChanges();
40.         
41.                 var courses = new List<Course>
42.                    {
43.                        new Course {CourseID = 1050, Title = "Chemistry",      Credits = 3, },
44.                        new Course {CourseID = 4022, Title = "Microeconomics", Credits = 3, },
45.                        new Course {CourseID = 4041, Title = "Macroeconomics", Credits = 3, },
46.                        new Course {CourseID = 1045, Title = "Calculus",       Credits = 4, },
47.                        new Course {CourseID = 3141, Title = "Trigonometry",   Credits = 4, },
48.                        new Course {CourseID = 2021, Title = "Composition",    Credits = 3, },
49.                        new Course {CourseID = 2042, Title = "Literature",     Credits = 4, }
50.                    };
51.                 courses.ForEach(s => context.Courses.AddOrUpdate(p => p.Title, s));
52.                 context.SaveChanges();
53.         
54.                 var enrollments = new List<Enrollment>
55.                    {
56.                        new Enrollment { 
57.                            StudentID = students.Single(s => s.LastName == "Alexander").StudentID, 
58.                            CourseID = courses.Single(c => c.Title == "Chemistry" ).CourseID, 
59.                            Grade = Grade.A 
60.                        },
61.                         new Enrollment { 
62.                            StudentID = students.Single(s => s.LastName == "Alexander").StudentID,
63.                            CourseID = courses.Single(c => c.Title == "Microeconomics" ).CourseID, 
64.                            Grade = Grade.C 
65.                         },                            
66.                         new Enrollment { 
67.                            StudentID = students.Single(s => s.LastName == "Alexander").StudentID,
68.                            CourseID = courses.Single(c => c.Title == "Macroeconomics" ).CourseID, 
69.                            Grade = Grade.B
70.                         },
71.                         new Enrollment { 
72.                             StudentID = students.Single(s => s.LastName == "Alonso").StudentID,
73.                            CourseID = courses.Single(c => c.Title == "Calculus" ).CourseID, 
74.                            Grade = Grade.B 
75.                         },
76.                         new Enrollment { 
77.                             StudentID = students.Single(s => s.LastName == "Alonso").StudentID,
78.                            CourseID = courses.Single(c => c.Title == "Trigonometry" ).CourseID, 
79.                            Grade = Grade.B 
80.                         },
81.                         new Enrollment {
82.                            StudentID = students.Single(s => s.LastName == "Alonso").StudentID,
83.                            CourseID = courses.Single(c => c.Title == "Composition" ).CourseID, 
84.                            Grade = Grade.B 
85.                         },
86.                         new Enrollment { 
87.                            StudentID = students.Single(s => s.LastName == "Anand").StudentID,
88.                            CourseID = courses.Single(c => c.Title == "Chemistry" ).CourseID
89.                         },
90.                         new Enrollment { 
91.                            StudentID = students.Single(s => s.LastName == "Anand").StudentID,
92.                            CourseID = courses.Single(c => c.Title == "Microeconomics").CourseID,
93.                            Grade = Grade.B         
94.                         },
95.                        new Enrollment { 
96.                            StudentID = students.Single(s => s.LastName == "Barzdukas").StudentID,
97.                            CourseID = courses.Single(c => c.Title == "Chemistry").CourseID,
98.                            Grade = Grade.B         
99.                         },
100.                       new Enrollment { 
101.                          StudentID = students.Single(s => s.LastName == "Li").StudentID,
102.                          CourseID = courses.Single(c => c.Title == "Composition").CourseID,
103.                          Grade = Grade.B         
104.                       },
105.                       new Enrollment { 
106.                          StudentID = students.Single(s => s.LastName == "Justice").StudentID,
107.                          CourseID = courses.Single(c => c.Title == "Literature").CourseID,
108.                          Grade = Grade.B         
109.                       }
110.                  };
111.       
112.               foreach (Enrollment e in enrollments)
113.               {
114.                  var enrollmentInDataBase = context.Enrollments.Where(
115.                      s =>
116.                           s.Student.StudentID == e.StudentID &&
117.                           s.Course.CourseID == e.CourseID).SingleOrDefault();
118.                  if (enrollmentInDataBase == null)
119.                  {
120.                     context.Enrollments.Add(e);
121.                  }
122.               }
123.               context.SaveChanges();
124.            }
125.         }
}

因爲此方法在建立或更新後調用,爲了不屢次插入同一數據,調用AddOrUpdate方法,第一個參數用來檢查數據是否已經存在。

context.Students.AddOrUpdate(p => p.LastName, s)

關於更多AddOrUpdate信息,請查看 Take care with EF 4.3 AddOrUpdate Method .

 

foreach (Enrollment e in enrollments)
{
    var enrollmentInDataBase = context.Enrollments.Where(
        s => s.Student.StudentID == e.Student.StudentID &&
             s.Course.CourseID == e.Course.CourseID).SingleOrDefault();
    if (enrollmentInDataBase == null)
    {
        context.Enrollments.Add(e);
    }
}

關於Seed中問題的調試,請查看 Seeding and Debugging Entity Framework (EF) DBs . 

  1. 編譯.
  2. 在 the Package Manager Console 執行命令: 

建立並執行 First Migration

2.  add-migration InitialCreate
update-database

 

 add-migration 命令將添加 [DateStamp]_InitialCreate.cs 文件到Migrations文件夾,文件中包含數據庫建立初始化信息。第一個參數 (InitialCreate) 做爲文件名,前面會加上時間戳.

 

 InitialCreate 文件代碼以下:

namespace ContosoUniversity.Migrations
{
    using System;
    using System.Data.Entity.Migrations;
    
    public partial class InitialCreate : DbMigration
    {
        public override void Up()
        {
            CreateTable(
                "dbo.Student",
                c => new
                    {
                        StudentID = c.Int(nullable: false, identity: true),
                        LastName = c.String(),
                        FirstMidName = c.String(),
                        EnrollmentDate = c.DateTime(nullable: false),
                    })
                .PrimaryKey(t => t.StudentID);
            
            CreateTable(
                "dbo.Enrollment",
                c => new
                    {
                        EnrollmentID = c.Int(nullable: false, identity: true),
                        CourseID = c.Int(nullable: false),
                        StudentID = c.Int(nullable: false),
                        Grade = c.Int(),
                    })
                .PrimaryKey(t => t.EnrollmentID)
                .ForeignKey("dbo.Course", t => t.CourseID, cascadeDelete: true)
                .ForeignKey("dbo.Student", t => t.StudentID, cascadeDelete: true)
                .Index(t => t.CourseID)
                .Index(t => t.StudentID);
            
            CreateTable(
                "dbo.Course",
                c => new
                    {
                        CourseID = c.Int(nullable: false),
                        Title = c.String(),
                        Credits = c.Int(nullable: false),
                    })
                .PrimaryKey(t => t.CourseID);
            
        }
        
        public override void Down()
        {
            DropIndex("dbo.Enrollment", new[] { "StudentID" });
            DropIndex("dbo.Enrollment", new[] { "CourseID" });
            DropForeignKey("dbo.Enrollment", "StudentID", "dbo.Student");
            DropForeignKey("dbo.Enrollment", "CourseID", "dbo.Course");
            DropTable("dbo.Course");
            DropTable("dbo.Enrollment");
            DropTable("dbo.Student");
        }
    }
}

The update-database 運行文件中的 Up 方法建立數據庫,而後調用 Seed方法.

名爲 ContosoUniversity的數據庫將被建立,  .mdf文件被存放在 App_Data 文件夾,如你在鏈接字符串指定的一致.

如下步驟是在VS中查看數據庫的操做,按圖所示操做便可,再也不翻譯。

  1. From the View menu, click Server Explorer.
  2. Click the Add Connection icon.

 

  1. If you are prompted with the Choose Data Source dialog, click Microsoft SQL Server, and then clickContinue.

  2. In the Add Connection dialog box,  enter  (localdb)\v11.0 for the Server Name. Under Select or enter a database name, select ContosoUniversity.

  3. Click OK.
  4. Expand  SchoolContext and then expand Tables.

  5. Right-click the Student table and click Show Table Data to see the columns that were created and the rows that were inserted into the table.

 

建立Student Controller and Views

 

  1. 右擊Controllers文件夾,選擇建立Controller,相關參數信息以下圖所示:

 

  1. Visual Studio 打開 Controllers\StudentController.cs file. 數據庫上下文對象已經建立
private SchoolContext db = new SchoolContext();

Index action method 從數據庫上下文獲取 Students屬性,返回學生列表:

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

The Student\Index.cshtml 視圖顯示了列表中的信息:

<table>
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.LastName)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.FirstMidName)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.EnrollmentDate)
        </th>
        <th></th>
    </tr>
 
@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.LastName)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.FirstMidName)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.EnrollmentDate)
        </td>
        <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>
    </tr>
}
  1. Press CTRL+F5 運行。

點擊Students 查看。

 

慣例

EF的這些慣例,使得以上所寫代碼很少:

  • 實體類名的複數形式做爲表名.
  • 實體類的屬性名做爲表的列名.
  •  ID 或 classnameID 做爲主鍵. 

慣例能夠沒必要遵照(如本文不用複數形式做爲表名),若是使用慣例或者覆蓋慣例,請查看後面的 Creating a More Complex Data Model 。更多信息請查看. Code First Conventions.

總結

使用 Entity Framework 和SQL Server Express 建立了一個簡單的web程序。隨後將學習如何完成基本的 CRUD (create, read, update, delete) 操做.

相關文章
相關標籤/搜索