Contoso 大学 - 1 - 为 ASP.NET MVC 应用程序创建 EF 数据模型

本文涉及的产品
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
云数据库 RDS SQL Server,基础系列 2核4GB
简介: 原文 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 大学 - 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 Framework  Continuing 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 使用数据上下文的名字作为数据库连接串的名字
相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS&nbsp;SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/sqlserver
目录
相关文章
|
28天前
|
存储 Shell Linux
快速上手基于 BaGet 的脚本自动化构建 .net 应用打包
本文介绍了如何使用脚本自动化构建 `.net` 应用的 `nuget` 包并推送到指定服务仓库。首先概述了 `BaGet`——一个开源、轻量级且高性能的 `NuGet` 服务器,支持多种存储后端及配置选项。接着详细描述了 `BaGet` 的安装、配置及使用方法,并提供了 `PowerShell` 和 `Bash` 脚本实例,用于自动化推送 `.nupkg` 文件。最后总结了 `BaGet` 的优势及其在实际部署中的便捷性。
60 10
|
2月前
|
Linux C++ Windows
【Azure 应用服务】Azure App Service(Windows)环境中如何让.NET应用调用SAP NetWeaver RFC函数
【Azure 应用服务】Azure App Service(Windows)环境中如何让.NET应用调用SAP NetWeaver RFC函数
【Azure 应用服务】Azure App Service(Windows)环境中如何让.NET应用调用SAP NetWeaver RFC函数
|
17天前
|
数据采集 JSON API
.NET 3.5 中 HttpWebRequest 的核心用法及应用
【9月更文挑战第7天】在.NET 3.5环境下,HttpWebRequest 类是处理HTTP请求的一个核心组件,它封装了HTTP协议的细节,使得开发者可以方便地发送HTTP请求并接收响应。本文将详细介绍HttpWebRequest的核心用法及其实战应用。
53 6
|
27天前
|
开发框架 前端开发 JavaScript
ASP.NET MVC 教程
ASP.NET 是一个使用 HTML、CSS、JavaScript 和服务器脚本创建网页和网站的开发框架。
28 7
|
2月前
|
Linux iOS开发 开发者
跨平台开发不再难:.NET Core如何让你的应用在Windows、Linux、macOS上自如游走?
【8月更文挑战第28天】本文提供了一份详尽的.NET跨平台开发指南,涵盖.NET Core简介、环境配置、项目结构、代码编写、依赖管理、构建与测试、部署及容器化等多个方面,帮助开发者掌握关键技术与最佳实践,充分利用.NET Core实现高效、便捷的跨平台应用开发与部署。
67 3
|
2月前
|
缓存 Java API
【揭秘】.NET高手不愿透露的秘密:如何让应用瞬间提速?
【8月更文挑战第28天】本文通过对比的方式,介绍了针对 .NET 应用性能瓶颈的优化方法。以一个存在响应延迟和并发处理不足的 Web API 项目为例,从性能分析入手,探讨了使用结构体减少内存分配、异步编程提高吞吐量、EF Core 惰性加载减少数据库访问以及垃圾回收机制优化等多个方面,帮助开发者全面提升 .NET 应用的性能和稳定性。通过具体示例,展示了如何在不同场景下选择最佳实践,以实现更高效的应用体验。
32 3
|
2月前
|
前端开发 JavaScript 开发工具
跨域联姻:React.NET——.NET应用与React的完美融合,解锁前后端高效协作新姿势。
【8月更文挑战第28天】探索React.NET,这是将热门前端框架React与强大的.NET后端无缝集成的创新方案。React以其组件化和虚拟DOM技术著称,能构建高性能、可维护的用户界面;.NET则擅长企业级应用开发。React.NET作为桥梁,使.NET应用轻松采用React构建前端,并优化开发流程与性能。通过直接托管React组件,.NET应用简化了部署流程,同时支持服务器端渲染(SSR),提升首屏加载速度与SEO优化。
28 1
|
2月前
|
存储 缓存 安全
.NET 在金融行业的应用:高并发交易系统的构建与优化之路
【8月更文挑战第28天】在金融行业,交易系统需具备高并发处理、低延迟及高稳定性和安全性。利用.NET构建此类系统时,可采用异步编程提升并发能力,优化数据库访问以降低延迟,使用缓存减少数据库访问频率,借助分布式事务确保数据一致性,并加强安全性措施。通过综合优化,满足金融行业的严苛要求。
33 1
|
2月前
|
大数据 开发工具 开发者
从零到英雄:.NET核心技术带你踏上编程之旅,构建首个应用,开启你的数字世界探险!
【8月更文挑战第28天】本文带领读者从零开始,使用强大的.NET平台搭建首个控制台应用。无论你是新手还是希望扩展技能的开发者,都能通过本文逐步掌握.NET的核心技术。从环境搭建到创建项目,再到编写和运行代码,详细步骤助你轻松上手。通过计算两数之和的小项目,你不仅能快速入门,还能为未来开发更复杂的应用奠定基础。希望本文为你的.NET学习之旅开启新篇章!
29 1
|
26天前
|
存储 开发框架 前端开发
ASP.NET MVC 迅速集成 SignalR
ASP.NET MVC 迅速集成 SignalR
38 0