第 4 部分:模型和数据访问

作者 :Jon Galloway

MVC 音乐存储是一个教程应用程序,它介绍并逐步说明如何使用 ASP.NET MVC 和 Visual Studio 进行 Web 开发。

MVC 音乐商店是一个轻量级的示例商店实现,用于在线销售音乐专辑,并实现基本的网站管理、用户登录和购物车功能。

本教程系列详细介绍了生成 ASP.NET MVC 音乐商店示例应用程序所执行的所有步骤。 第 4 部分介绍模型和数据访问。

到目前为止,我们刚刚将“虚拟数据”从控制器传递到视图模板。 现在,我们已准备好挂接真正的数据库。 在本教程中,我们将介绍如何将 SQL Server Compact Edition (通常称为 SQL CE) 用作数据库引擎。 SQL CE 是一个基于文件的免费嵌入式数据库,不需要任何安装或配置,这使得本地开发非常方便。

使用 Entity Framework Code-First 进行数据库访问

我们将使用包含在 ASP.NET MVC 3 项目中的 Entity Framework (EF) 支持来查询和更新数据库。 EF 是一种灵活的对象关系映射, (ORM) 数据 API,使开发人员能够以面向对象的方式查询和更新数据库中存储的数据。

实体框架版本 4 支持名为“代码优先”的开发范例。 代码优先允许通过从“普通老”CLR 对象 () 编写简单类(也称为 POCO)来创建模型对象,甚至可以从类动态创建数据库。

对模型类的更改

本教程将利用 Entity Framework 中的数据库创建功能。 不过,在执行此操作之前,让我们对模型类进行一些细微的更改,以添加稍后将使用的一些内容。

添加艺术家模型类

我们的专辑将与艺术家相关联,因此我们将添加一个简单的模型类来描述艺术家。 使用如下所示的代码将一个新类添加到名为 Artist.cs 的 Models 文件夹。

namespace MvcMusicStore.Models
{
    public class Artist
    {
        public int ArtistId { get; set; }
        public string Name { get; set; }
    }
}

更新模型类

更新 Album 类,如下所示。

namespace MvcMusicStore.Models
{
    public class Album
    {
        public int      AlbumId     { get; set; }
        public int      GenreId     { get; set; }
        public int      ArtistId    { get; set; }
        public string   Title       { get; set; }
        public decimal  Price       { get; set; }
        public string   AlbumArtUrl { get; set; }
        public Genre    Genre       { get; set; }
        public Artist   Artist      { get; set; }
    }
}

接下来,对 Genre 类进行以下更新。

using System.Collections.Generic;
 
namespace MvcMusicStore.Models
{
    public partial class Genre
    {
        public int      GenreId     { get; set; }
        public string   Name        { get; set; }
        public string   Description { get; set; }
        public List<Album> Albums   { get; set; }
    }
}

添加App_Data文件夹

我们将向项目添加App_Data目录,以保存SQL Server Express数据库文件。 App_Data 是 ASP.NET 中的特殊目录,它已具有正确的数据库访问安全访问权限。 在“项目”菜单中,选择“添加 ASP.NET 文件夹”,然后选择“App_Data”。

用于添加 A S P 的“项目”菜单的屏幕截图。N E T 文件夹,用于选择应用数据。

在 web.config 文件中创建连接字符串

我们将向网站的配置文件添加几行,以便 Entity Framework 了解如何连接到数据库。 双击位于项目根目录中的Web.config文件。

解决方案资源管理器中用于创建连接字符串的 Web 配置文件的屏幕截图。

滚动到此文件的底部,并在最后一 <行正上方添加 connectionStrings> 部分,如下所示。

<connectionStrings>
    <add name="MusicStoreEntities"
     connectionString="Data Source=|DataDirectory|MvcMusicStore.sdf"
     providerName="System.Data.SqlServerCe.4.0"/>
  </connectionStrings>  
</configuration>

添加上下文类

右键单击 Models 文件夹,并添加名为 MusicStoreEntities.cs 的新类。

用于添加上下文类的 Models 文件夹的屏幕截图。

此类将表示 Entity Framework 数据库上下文,并将为我们处理创建、读取、更新和删除操作。 此类的代码如下所示。

using System.Data.Entity;
 
namespace MvcMusicStore.Models
{
    public class MusicStoreEntities : DbContext
    {
        public DbSet<Album> Albums { get; set; }
        public DbSet<Genre> Genres { get; set; }
    }
}

就是这样 - 没有其他配置、特殊接口等。通过扩展 DbContext 基类,MusicStoreEntities 类能够为我们处理数据库操作。 现在,我们已经挂接了这些内容,让我们向模型类添加更多属性,以利用数据库中的一些其他信息。

添加我们的商店目录数据

我们将利用实体框架中的一项功能,该功能将“种子”数据添加到新创建的数据库中。 这将使用流派、艺术家和专辑列表预先填充我们的商店目录。 MvcMusicStore-Assets.zip下载(包括本教程前面使用的网站设计文件)包含一个包含此种子数据的类文件,位于名为 Code 的文件夹中。

在“Code/Models”文件夹中,找到 SampleData.cs 文件并将其放入项目中的 Models 文件夹,如下所示。

用于查找示例数据 C S 文件并添加存储目录数据的 Code 或 Models 文件夹的屏幕截图。

现在,我们需要添加一行代码,以告知 Entity Framework 有关该 SampleData 类的信息。 双击项目根目录中的 Global.asax 文件将其打开,并将以下行添加到 Application_Start 方法顶部。

protected void Application_Start()
{
    System.Data.Entity.Database.SetInitializer(
    new MvcMusicStore.Models.SampleData());
    AreaRegistration.RegisterAllAreas();
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
 }

此时,我们已完成为项目配置 Entity Framework 所需的工作。

查询数据库

现在,让我们更新 StoreController,而不是使用“虚拟数据”,而是调用数据库来查询其所有信息。 首先,我们将在 StoreController 上声明一个字段来保存名为 storeDB 的 MusicStoreEntities 类的实例:

public class StoreController : Controller
{
    MusicStoreEntities storeDB = new MusicStoreEntities();

更新存储索引以查询数据库

MusicStoreEntities 类由 Entity Framework 维护,并公开数据库中每个表的集合属性。 让我们更新 StoreController 的索引操作,以检索数据库中的所有流派。 以前,我们通过对字符串数据进行硬编码来执行此操作。 现在,我们可以改用 Entity Framework 上下文 Generes 集合:

public ActionResult Index()
{
    var genres = storeDB.Genres.ToList();
    return View(genres);
 }

无需更改视图模板,因为我们仍然返回之前返回的相同 StoreIndexViewModel - 现在只是从数据库返回实时数据。

当我们再次运行项目并访问“/Store”URL 时,现在会看到数据库中所有流派的列表:

数据库中所有流派列表的屏幕截图。

更新应用商店浏览和详细信息以使用实时数据

使用 /Store/Browse?genre=[some-genre] 操作方法,我们将按名称搜索流派。 我们只需要一个结果,因为我们不应该有两个条目用于同一流派名称,因此可以使用 。LINQ 中的单一 () 扩展,用于查询相应的流派对象,如以下 (尚未键入此) :

var example = storeDB.Genres.Single(g => g.Name == "Disco");

Single 方法采用 Lambda 表达式作为参数,该参数指定我们需要单个 Genre 对象,使其名称与定义的值匹配。 在上述情况下,我们将加载具有与 Disco 匹配的 Name 值的单个 Genre 对象。

我们将利用实体框架功能,该功能允许我们在检索 Genre 对象时指示要加载的其他相关实体。 此功能称为“查询结果整形”,使我们能够减少访问数据库以检索所需的所有信息所需的次数。 我们希望预提取我们检索的流派的专辑,因此我们将更新查询以包括从 Genres.Include (“Albums”) ,以指示我们还需要相关的专辑。 这更高效,因为它会在单个数据库请求中检索我们的流派和专辑数据。

在说明不通的情况下,我们更新的“浏览控制器”操作如下所示:

public ActionResult Browse(string genre)
{
    // Retrieve Genre and its Associated Albums from database
    var genreModel = storeDB.Genres.Include("Albums")
        .Single(g => g.Name == genre);

    return View(genreModel);
}

我们现在可以更新 Microsoft Store 浏览视图,以显示每个流派中可用的相册。 打开 /Views/Store/Browse.cshtml) 中找到 (视图模板,并添加带项目符号的专辑列表,如下所示。

@model MvcMusicStore.Models.Genre
@{
    ViewBag.Title = "Browse";
}
<h2>Browsing Genre: @Model.Name</h2>
<ul>
    @foreach (var album in Model.Albums)
    {
        <li>
            @album.Title
        </li>
    }
</ul>

运行我们的应用程序并浏览到 /Store/Browse?genre=Jazz 显示我们的结果现在正在从数据库拉取,其中显示了所选流派中的所有专辑。

从数据库拉取结果的屏幕截图显示所选流派中的所有相册。

我们将对 /Store/Details/[id] URL 进行相同的更改,并将虚拟数据替换为数据库查询,该查询将加载 ID 与参数值匹配的相册。

public ActionResult Details(int id)
{
    var album = storeDB.Albums.Find(id);
 
    return View(album);
}

运行应用程序并浏览到 /Store/Details/1 显示现在正在从数据库拉取结果。

“应用商店详细信息”页的屏幕截图显示,也正在从数据库拉取结果。

现在,“应用商店详细信息”页面已设置为按“相册 ID”显示相册,接下来更新 “浏览 ”视图以链接到“详细信息”视图。 我们将使用 Html.ActionLink,就像在上一部分结束时从应用商店索引链接到应用商店浏览所做的那样。 浏览视图的完整源如下所示。

@model MvcMusicStore.Models.Genre
@{
    ViewBag.Title = "Browse";
}
<h2>Browsing Genre: @Model.Name</h2>
<ul>
    @foreach (var album in Model.Albums)
    {
        <li>
            @Html.ActionLink(album.Title,
"Details", new { id = album.AlbumId })
        </li>
    }
</ul>

现在,我们可以从“应用商店”页面浏览到“流派”页面,其中列出了可用的相册,通过单击某个相册,可以查看该相册的详细信息。

能够从应用商店页面浏览到流派页面的屏幕截图。