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

本文涉及的产品
云数据库 RDS SQL Server,独享型 2核4GB
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
简介: 原文 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
目录
相关文章
|
18天前
|
机器学习/深度学习 人工智能 Cloud Native
洞察.NET 技术的前沿应用
【7月更文挑战第4天】**洞察.NET技术前沿:.NET Core跨平台崛起,云原生与AI应用深化。ML.NET、TensorFlow.NET助力机器学习,Xamarin与MAUI统一跨平台UI。Azure云服务支持下,.NET引领软件开发新趋势。**
27 5
|
1月前
|
设计模式 存储 前端开发
MVC(Model-View-Controller)是一种软件设计模式,用于将应用程序的输入逻辑、业务逻辑和用户界面逻辑分离
【6月更文挑战第17天】**MVC模式**是软件设计模式,用于分离输入逻辑、业务逻辑和用户界面。模型处理数据和业务,视图展示数据,控制器协调两者响应用户请求。优点包括:关注点分离、提高开发效率、简化测试、支持多视图及便于大型项目管理。
28 3
|
18天前
|
设计模式 前端开发 数据库
深入理解MVC设计模式:构建高效Web应用程序的基石
【7月更文挑战第4天】在软件工程领域,设计模式是解决常见问题的一系列经过验证的方法。其中,Model-View-Controller(MVC)设计模式自诞生以来,便成为了构建用户界面,特别是Web应用程序的黄金标准。MVC通过将应用程序逻辑分离为三个核心组件,提高了代码的可维护性、可扩展性和重用性。本文将深入探讨MVC设计模式的原理,并通过一个简单的代码示例展示其应用。
43 0
|
1月前
|
开发框架 前端开发 .NET
LIMS(实验室)信息管理系统源码、有哪些应用领域?采用C# ASP.NET dotnet 3.5 开发的一套实验室信息系统源码
集成于VS 2019,EXT.NET前端和ASP.NET后端,搭配MSSQL 2018数据库。系统覆盖样品管理、数据分析、报表和项目管理等实验室全流程。应用广泛,包括生产质检(如石化、制药)、环保监测、试验研究等领域。随着技术发展,现代LIMS还融合了临床、电子实验室笔记本和SaaS等功能,以满足复杂多样的实验室管理需求。
39 3
LIMS(实验室)信息管理系统源码、有哪些应用领域?采用C# ASP.NET dotnet 3.5 开发的一套实验室信息系统源码
|
18天前
|
人工智能 开发框架 Devops
.NET技术概览:** 本文探讨了.NET的核心特性,包括多语言支持、Common Language Runtime、丰富的类库和跨平台能力,强调其在企业级、Web、移动及游戏开发中的应用。
【7月更文挑战第4天】.NET技术概览:** 本文探讨了.NET的核心特性,包括多语言支持、Common Language Runtime、丰富的类库和跨平台能力,强调其在企业级、Web、移动及游戏开发中的应用。此外,讨论了.NET如何通过性能优化、DevOps集成、AI与ML支持以及开源策略应对未来挑战,为开发者提供强大工具,共创软件开发新篇章。
20 3
|
18天前
|
人工智能 物联网 开发者
**.NET技术革新赋能软件开发:从.NET 5的性能飞跃、跨平台支持,到微服务、物联网、AI和游戏开发的广泛应用。
【7月更文挑战第4天】**.NET技术革新赋能软件开发:从.NET 5的性能飞跃、跨平台支持,到微服务、物联网、AI和游戏开发的广泛应用。随着云集成深化、开源社区壮大,未来将聚焦性能优化、云原生应用及新兴技术融合,培养更多开发者,驱动软件创新。**
82 1
|
29天前
|
网络协议 Java 程序员
TCP/IP协议栈是网络通信基础,Java的`java.net`包提供工具,使开发者能利用TCP/IP创建网络应用
【6月更文挑战第23天】 **TCP/IP协议栈是网络通信基础,它包含应用层(HTTP, FTP等)、传输层(TCP, UDP)、网络层(IP)、数据链路层(帧, MAC地址)和物理层(硬件信号)。Java的`java.net`包提供工具,使开发者能利用TCP/IP创建网络应用,如Socket和ServerSocket用于客户端和服务器通信。**
35 3
|
16天前
|
开发框架 监控 NoSQL
.NET开源的实时应用监控系统 - WatchDog
.NET开源的实时应用监控系统 - WatchDog
|
18天前
|
人工智能 前端开发 开发工具
.NET技术探析:优势、创新应用及挑战。
【7月更文挑战第4天】**.NET技术探析:优势、创新应用及挑战。本文分三部分展开,阐述了.NET作为统一多语言开发平台的核心优势,如强大的Visual Studio工具、跨平台能力与丰富的类库;探讨了其在企业级、Web、移动及游戏开发中的创新角色;并指出面临性能优化、容器化、AI集成等挑战及未来开源社区驱动的发展机遇。通过理解与应对,开发者可借助.NET推动软件开发进步。**
20 0
|
1月前
|
开发框架 JSON .NET
学习ASP.NET 中的 默认应用程序配置源
默认主机配置源 使用命令行配置提供程序的命令行参数
22 2