使用 Entity Framework 创建模型类 (C#)

Microsoft

本教程介绍如何将 ASP.NET MVC 与 Microsoft Entity Framework 配合使用。 了解如何使用实体向导创建 ADO.NET 实体数据模型。 在本教程中,我们将生成一个 Web 应用程序,该应用程序演示如何使用实体框架选择、插入、更新和删除数据库数据。

本教程的目的是说明在生成 ASP.NET MVC 应用程序时如何使用 Microsoft 实体框架创建数据访问类。 本教程假定以前不了解 Microsoft 实体框架。 本教程结束时,你将了解如何使用实体框架选择、插入、更新和删除数据库记录。

Microsoft 实体框架是一种对象关系映射 (O/RM) 工具,可用于从数据库自动生成数据访问层。 使用实体框架,可以避免手动生成数据访问类的繁琐工作。

为了说明如何将 Microsoft 实体框架与 ASP.NET MVC 配合使用,我们将生成一个简单的示例应用程序。 我们将创建一个电影数据库应用程序,用于显示和编辑电影数据库记录。

本教程假定你具有 Visual Studio 2008 或 Visual Web Developer 2008 和 Service Pack 1。 需要使用 Service Pack 1 才能使用实体框架。 可以从以下地址下载 Visual Studio 2008 Service Pack 1 或 Visual Web Developer with Service Pack 1:

https://www.asp.net/downloads/

注意

ASP.NET MVC 与 Microsoft 实体框架之间没有重要的连接。 实体框架有几种替代方法可用于 ASP.NET MVC。 例如,可以使用其他 O/RM 工具(如 Microsoft LINQ to SQL、NHibernate 或 SubSonic)生成 MVC 模型类。

创建电影示例数据库

Movie Database 应用程序使用名为 Movies 的数据库表,该表包含以下列:

列名 数据类型 是否允许 Null? 是主键吗?
ID int False True
标题 nvarchar(100) False False
导演 nvarchar(100) False False

可以通过执行以下步骤将此表添加到 ASP.NET MVC 项目:

  1. 右键单击解决方案资源管理器窗口中App_Data文件夹,然后选择菜单选项“添加”、“新建项”。
  2. 在“添加新项”对话框中,选择“SQL Server数据库”,为数据库命名为 MoviesDB.mdf,然后单击“添加”按钮。
  3. 双击 MoviesDB.mdf 文件以打开“服务器资源管理器/数据库资源管理器”窗口。
  4. 展开 MoviesDB.mdf 数据库连接,右键单击“表”文件夹,然后选择菜单选项 “添加新表”。
  5. 在“表Designer,添加”Id“、”标题“和”控制器“列。
  6. 单击“ 保存 ”按钮 (具有软盘) 图标,以保存名为“电影”的新表。

创建 Movies 数据库表后,应向该表添加一些示例数据。 右键单击“电影”表,然后选择菜单选项 “显示表数据”。 可以将假电影数据输入到显示的网格中。

创建 ADO.NET 实体数据模型

若要使用实体框架,需要创建实体数据模型。 可以利用 Visual Studio 实体数据模型向导 从数据库自动生成实体数据模型。

按照以下步骤操作:

  1. 右键单击“解决方案资源管理器”窗口中的“模型”文件夹,然后选择菜单选项“添加”、“新建项”。
  2. “添加新项 ”对话框中,选择“数据”类别 (请参阅图 1) 。
  3. 选择 ADO.NET 实体数据模型 模板,为实体数据模型命名为 MoviesDBModel.edmx,然后单击 “添加 ”按钮。 单击“ 添加” 按钮将启动数据模型向导。
  4. “选择模型内容” 步骤中,选择“ 从数据库生成 ”选项,然后单击“ 下一步 ”按钮 (请参阅图 2) 。
  5. “选择数据连接 ”步骤中,选择 MoviesDB.mdf 数据库连接,输入实体连接设置名称 MoviesDBEntities,然后单击“ 下一步 ”按钮 (请参阅图 3) 。
  6. “选择数据库对象” 步骤中,选择“Movie”数据库表并单击“ 完成 ”按钮 (请参阅图 4) 。

完成这些步骤后,ADO.NET 实体数据模型Designer (实体Designer) 将打开。

图 1 - 创建新的实体数据模型

clip_image002

图 2 - 选择模型内容步骤

clip_image004

图 3 - 选择数据连接

clip_image006

图 4 - 选择数据库对象

clip_image008

修改 ADO.NET 实体数据模型

创建实体数据模型后,可以通过利用实体Designer (来修改模型,请参阅图 5) 。 可随时打开实体Designer,方法是双击“解决方案资源管理器”窗口中的 Models 文件夹中包含的 MoviesDBModel.edmx 文件。

图 5 - ADO.NET 实体数据模型Designer

clip_image010

例如,可以使用实体Designer更改实体模型数据向导生成的类的名称。 向导创建了名为 Movies 的新数据访问类。 换句话说,向导为类赋予了与数据库表完全相同的名称。 由于我们将使用此类来表示特定的 Movie 实例,因此应将该类从 Movies 重命名为 Movie。

如果要重命名实体类,可以双击实体Designer中的类名,然后输入新名称 (见图 6) 。 或者,在“实体”Designer中选择实体后,可以在属性窗口中更改实体的名称。

图 6 - 更改实体名称

clip_image012

请记住,在修改实体数据模型后,请单击“保存”按钮 (软盘) 图标。 实体Designer在后台生成一组 C# 类。 可以通过打开 MoviesDBModel 来查看这些类。解决方案资源管理器窗口中的 Designer.cs 文件。

请勿修改 Designer.cs 文件中的代码,因为下次使用 Entity Designer时将覆盖所做的更改。 如果要扩展 Designer.cs 文件中定义的实体类的功能,则可以在单独的文件中创建分部类

使用实体框架选择数据库记录

让我们通过创建一个显示电影记录列表的页面开始构建电影数据库应用程序。 清单 1 中的主控制器公开名为 Index () 的操作。 Index () 操作利用实体框架从 Movie 数据库表返回所有电影记录。

列表 1 – Controllers\HomeController.cs

using System.Linq;
using System.Web.Mvc;
using MovieEntityApp.Models;

namespace MovieEntityApp.Controllers
{
    [HandleError]
    public class HomeController : Controller
    {
        MoviesDBEntities _db;

        public HomeController()
        {
            _db = new MoviesDBEntities();
        }

        public ActionResult Index()
        {
            ViewData.Model = _db.MovieSet.ToList();
            return View();
        }

    }
}

请注意,清单 1 中的控制器包含构造函数。 构造函数初始化名为 _db 的类级字段。 _db字段表示由 Microsoft 实体框架生成的数据库实体。 _db字段是由 Entity Designer生成的 MoviesDBEntities 类的实例。

若要在 Home 控制器中使用MoviesDBEntities 类,必须将 MovieEntityApp.Models 命名空间 (MVCProjectName 导入。模型) 。

在 Index () 操作中使用_db字段从 Movies 数据库表中检索记录。 表达式_db。MovieSet 表示 Movies 数据库表中的所有记录。 ToList () 方法用于将电影集转换为 Movie 对象的泛型集合, (List<Movie>) 。

电影记录是在 LINQ to Entities 的帮助下检索的。 清单 1 中的 Index () 操作使用 LINQ 方法语法 检索数据库记录集。 如果需要,可以改用 LINQ 查询语法 。 以下两个语句执行相同的操作:

ViewData.Model = _db.MovieSet.ToList();
ViewData.Model = (from m in _db.MovieSet select m).ToList();

使用你认为最直观的 LINQ 语法(方法语法或查询语法)。 这两种方法在性能上没有差异 - 唯一的区别在于风格。

清单 2 中的视图用于显示电影记录。

清单 2 - Views\Home\Index.aspx

<%@ Page Language="C#"  
  Inherits="System.Web.Mvc.ViewPage<List<MovieEntityApp.Models.Movie>>" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Index</title>
</head>
<body>
    <div>
    
<% foreach (var m in ViewData.Model)
   { %>

    Title: <%= m.Title %>
    <br />
    Director: <%= m.Director %>
    <br />
    <%= Html.ActionLink("Edit", "Edit", new { id = m.Id })%>
    <%= Html.ActionLink("Delete", "Delete", new { id = m.Id })%>
       
        <hr />
<% } %>

<%= Html.ActionLink("Add Movie", "Add") %>
    
    </div>
</body>
</html>

清单 2 中的视图包含 一个 foreach 循环,循环访问每个电影记录并显示电影记录的“标题”和“导演”属性的值。 请注意,每条记录旁边都显示“编辑”和“删除”链接。 此外,视图底部会显示“添加影片”链接, (请参阅图 7) 。

图 7 - 索引视图

clip_image014

“索引”视图是 类型化视图。 索引视图包含一个 <%@ Page %> 指令,其中包含 一个 Inherits 属性,该属性将 Model 属性强制转换为 Movie 对象的强类型泛型 List 集合, (List<Movie) 。

使用实体框架插入数据库记录

可以使用 Entity Framework 轻松地将新记录插入数据库表。 清单 3 包含添加到主控制器类的两个新操作,可用于将新记录插入 Movie 数据库表。

清单 3 - Controllers\HomeController.cs (添加方法)

public ActionResult Add()
{
    return View();
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Add(FormCollection form)
{
    var movieToAdd = new Movie();

    // Deserialize (Include white list!)
    TryUpdateModel(movieToAdd, new string[] { "Title", "Director" }, form.ToValueProvider());

    // Validate
    if (String.IsNullOrEmpty(movieToAdd.Title))
        ModelState.AddModelError("Title", "Title is required!");
    if (String.IsNullOrEmpty(movieToAdd.Director))
        ModelState.AddModelError("Director", "Director is required!");

    // If valid, save movie to database
    if (ModelState.IsValid)
    {
        _db.AddToMovieSet(movieToAdd);
        _db.SaveChanges();
        return RedirectToAction("Index");
    }

    // Otherwise, reshow form
    return View(movieToAdd);
}

第一个 Add () 操作仅返回视图。 视图包含用于添加新电影数据库记录的窗体 (请参阅图 8) 。 提交表单时,将调用第二个 Add () 操作。

请注意,第二个 Add () 操作是使用 AcceptVerbs 属性修饰的。 仅当执行 HTTP POST 操作时,才能调用此操作。 换句话说,只能在发布 HTML 表单时调用此操作。

第二个 Add () 操作在 ASP.NET MVC TryUpdateModel () 方法的帮助下创建 Entity Framework Movie 类的新实例。 TryUpdateModel () 方法采用传递给 Add () 方法的 FormCollection 中的字段,并将这些 HTML 表单字段的值分配给 Movie 类。

使用实体框架时,在使用 TryUpdateModel 或 UpdateModel 方法更新实体类的属性时,必须提供属性的“安全列表”。

接下来,Add () 操作执行一些简单的表单验证。 该操作验证 Title 和 Director 属性是否具有值。 如果存在验证错误,则会将验证错误消息添加到 ModelState。

如果没有验证错误,则会在实体框架的帮助下将新的电影记录添加到 Movies 数据库表。 新记录将使用以下两行代码添加到数据库中:

_db.AddToMovieSet(movieToAdd);
_db.SaveChanges();

第一行代码将新的 Movie 实体添加到实体框架跟踪的电影集。 第二行代码保存对要跟踪回基础数据库的电影所做的任何更改。

图 8 - 添加视图

clip_image016

使用实体框架更新数据库记录

使用 Entity Framework 编辑数据库记录的方法与刚插入新数据库记录的方法几乎相同。 清单 4 包含两个名为 Edit () 的新控制器操作。 第一个 Edit () 操作返回用于编辑电影记录的 HTML 表单。 第二个 Edit () 操作尝试更新数据库。

列表 4 - Controllers\HomeController.cs (Edit 方法)

public ActionResult Edit(int id)
{
    // Get movie to update
    var movieToUpdate = _db.MovieSet.First(m => m.Id == id);

    ViewData.Model = movieToUpdate;
    return View();
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(FormCollection form)
{
    // Get movie to update
    var id = Int32.Parse(form["id"]);
    var movieToUpdate = _db.MovieSet.First(m => m.Id == id);

    // Deserialize (Include white list!)
    TryUpdateModel(movieToUpdate, new string[] { "Title", "Director" }, form.ToValueProvider());

    // Validate
    if (String.IsNullOrEmpty(movieToUpdate.Title))
        ModelState.AddModelError("Title", "Title is required!");
    if (String.IsNullOrEmpty(movieToUpdate.Director))
        ModelState.AddModelError("Director", "Director is required!");

    // If valid, save movie to database
    if (ModelState.IsValid)
    {
        _db.SaveChanges();
        return RedirectToAction("Index");
    }

    // Otherwise, reshow form
    return View(movieToUpdate);
}

第二个 Edit () 操作首先从数据库中检索与正在编辑的电影的 ID 匹配的 Movie 记录。 以下 LINQ to Entities 语句抓取与特定 ID 匹配的第一条数据库记录:

var movieToUpdate = _db.MovieSet.First(m => m.Id == id);

接下来,使用 TryUpdateModel () 方法将 HTML 窗体字段的值分配给电影实体的属性。 请注意,提供了安全列表来指定要更新的确切属性。

接下来,执行一些简单的验证,以验证“电影标题”和“导演”属性是否具有值。 如果任一属性缺少值,则会向 ModelState 添加验证错误消息,ModelState.IsValid 返回值 false。

最后,如果没有验证错误,则通过调用 SaveChanges () 方法使用任何更改更新基础 Movies 数据库表。

编辑数据库记录时,需要将正在编辑的记录的 ID 传递给执行数据库更新的控制器操作。 否则,控制器操作将不知道在基础数据库中更新哪个记录。 列表 5 中包含的“编辑”视图包含一个隐藏的窗体字段,该字段表示正在编辑的数据库记录的 ID。

列表 5 - Views\Home\Edit.aspx

<%@ Page Language="C#" 
  Inherits="System.Web.Mvc.ViewPage<MovieEntityApp.Models.Movie>" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Edit</title>
    <style type="text/css">
    
    .input-validation-error
    {
        background-color:Yellow;
    }
    
    </style>    
</head>
<body>
    <div>

<h1>Edit Movie</h1>

<form method="post" action="/Home/Edit">

    <!-- Include Hidden Id -->
    <%= Html.Hidden("id") %>

    Title:
    <br />
    <%= Html.TextBox("title") %>
    
    <br /><br />
    Director:
    <br />
    <%= Html.TextBox("director") %>
    
    <br /><br />
    <input type="submit" value="Edit Movie" />
</form>
    
    </div>
</body>
</html>

使用实体框架删除数据库记录

在本教程中,我们需要处理的最后一个数据库操作是删除数据库记录。 可以使用清单 6 中的控制器操作删除特定的数据库记录。

清单 6 -- \Controllers\HomeController.cs (Delete 操作)

public ActionResult Delete(int id)
{
    // Get movie to delete
    var movieToDelete = _db.MovieSet.First(m => m.Id == id);

    // Delete 
    _db.DeleteObject(movieToDelete);
    _db.SaveChanges();

    // Show Index view
    return RedirectToAction("Index");
}

Delete () 操作首先检索与传递给操作的 ID 匹配的 Movie 实体。 接下来,通过调用 DeleteObject () 方法后跟 SaveChanges () 方法,从数据库中删除影片。 最后,将用户重定向回索引视图。

总结

本教程的目的是演示如何利用 ASP.NET MVC 和 Microsoft 实体框架来构建数据库驱动的 Web 应用程序。 你已了解如何生成一个应用程序,使你能够选择、插入、更新和删除数据库记录。

首先,我们讨论了如何使用实体数据模型向导从 Visual Studio 中生成实体数据模型。 接下来,你将了解如何使用 LINQ to Entities 从数据库表检索一组数据库记录。 最后,我们使用 Entity Framework 插入、更新和删除数据库记录。