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) 操做.

相关文章
相关标签/搜索