使用 Entity Framework 创建模型类 (VB)

Microsoft

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

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

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

注意

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

为了说明如何将 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/

创建电影示例数据库

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

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

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

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

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

列表 1 – Controllers\HomeController.vb

<HandleError()> _
Public Class HomeController
    Inherits System.Web.Mvc.Controller

    Private _db As MoviesDBEntities

    Public Sub New()
        _db = New MoviesDBEntities()
    End Sub

    Public Function Index()
        ViewData.Model = _db.MovieSet.ToList()
        Return View()
    End Function

End Class

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

在 Index () 操作中使用_db字段从 Movies 数据库表中检索记录。 表达式_db。MovieSet 表示 Movies 数据库表中的所有记录。 ToList () 方法用于将电影集转换为 Movie 对象的泛型集合:List ( Of 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="VB" 
  Inherits="System.Web.Mvc.ViewPage(Of List(Of MvcApplication1.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>
    
<%  For Each m In Model%>

    Title: <%= m.Title %>
    <br />
    Director: <%= m.Director %>
    <br />
    <%=Html.ActionLink("Edit", "Edit", New With {.id = m.Id})%>
    <%=Html.ActionLink("Delete", "Delete", New With {.id = m.Id})%>
       
        <hr />
<% Next%>
    
    <%= Html.ActionLink("Add Movie", "Add") %>
    
    </div>
</body>
</html>

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

图 7 - 索引视图

clip_image014

索引视图是 类型化视图。 索引视图具有包含 <Inherits 属性的 %@ Page %> 指令。 Inherits 属性将 ViewData.Model 属性强制转换为 Movie 对象的强类型泛型 List 集合 - List (Of Movie) 。

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

可以使用实体框架轻松地将新记录插入数据库表。 列表 3 包含添加到 Home 控制器类的两个新操作,可用于将新记录插入 Movie 数据库表。

列表 3 – Controllers\HomeController.vb (添加方法)

<HandleError()> _
Public Class HomeController
    Inherits System.Web.Mvc.Controller

    Public Function Add()
        Return View()
    End Function

    <AcceptVerbs(HttpVerbs.Post)> _
    Public Function Add(ByVal form As FormCollection)
        Dim movieToAdd As New Movie()

        ' Deserialize (Include white list!)
        TryUpdateModel(movieToAdd, New String() {"Title", "Director"}, form.ToValueProvider())

        ' Validate
        If String.IsNullOrEmpty(movieToAdd.Title) Then
            ModelState.AddModelError("Title", "Title is required!")
        End If
        If String.IsNullOrEmpty(movieToAdd.Director) Then
            ModelState.AddModelError("Director", "Director is required!")
        End If

        ' If valid, save movie to database
        If (ModelState.IsValid) Then
            _db.AddToMovieSet(movieToAdd)
            _db.SaveChanges()
            Return RedirectToAction("Index")
        End If

        ' Otherwise, reshow form
        Return View(movieToAdd)
    End Function

End Class

第一个 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

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

可以使用实体框架编辑数据库记录,就像我们刚才插入新数据库记录的方法一样。 列表 4 包含两个名为 Edit () 的新控制器操作。 第一个 Edit () 操作返回用于编辑电影记录的 HTML 窗体。 第二个 Edit () 操作尝试更新数据库。

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

<HandleError()> _
Public Class HomeController
    Inherits System.Web.Mvc.Controller

    Public Function Edit(ByVal id As Integer)
        ' Get movie to update
        Dim movieToUpdate As Movie = _db.MovieSet.First(Function(m) m.Id = id)
        ViewData.Model = movieToUpdate
        Return View()
    End Function

    <AcceptVerbs(HttpVerbs.Post)> _
    Public Function Edit(ByVal form As FormCollection)

        ' Get movie to update
        Dim id As Integer = Integer.Parse(form("id"))
        Dim movieToUpdate As Movie = _db.MovieSet.First(Function(m) m.Id = id)

        ' Deserialize (Include white list!)
        TryUpdateModel(movieToUpdate, New String() {"Title", "Director"}, form.ToValueProvider)

        ' Validate
        If String.IsNullOrEmpty(movieToUpdate.Title) Then
            ModelState.AddModelError("Title", "Title is required!")
        End If
        If String.IsNullOrEmpty(movieToUpdate.Director) Then
            ModelState.AddModelError("Director", "Director is required!")
        End If

        ' If valid, save movie to database
        If (ModelState.IsValid) Then
            _db.SaveChanges()
            Return RedirectToAction("Index")
        End If

        ' Otherwise, reshow form
        Return View(movieToUpdate)
    End Function

End Class

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

Dim movieToUpdate As Movie = _db.MovieSet.First(Function(m) m.Id = id)

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

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

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

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

列表 5 – Views\Home\Edit.aspx

<%@ Page Language="VB" Inherits="System.Web.Mvc.ViewPage(Of MvcApplication1.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 id="Head1" 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.vb (Delete 操作)

<HandleError()> _
Public Class HomeController
    Inherits System.Web.Mvc.Controller

    Public Function Delete(ByVal id As Integer)
        ' Get movie to delete
        Dim movieToDelete As Movie = _db.MovieSet.First(Function(m) m.Id = id)

        ' Delete 
        _db.DeleteObject(movieToDelete)
        _db.SaveChanges()

        ' Show Index view
        Return RedirectToAction("Index")
    End Function

End Class

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

总结

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

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