Asp.net MVC 模型(Entity Framework、LinqToSql、显示数据库数据表格)
Asp.Net MVC 模型(使用Entity Framework创建模型类) - Part.1
这篇教程的目的是解释在创建ASP.NET MVC应用程序时,如何使用Microsoft Entity Framework来创建数据访问类。这篇教程假设你事先对Microsoft Entity Framework没有任何的了解。读完本篇教程,你将会理解如何使用Entity Framework来选择、插入、更新和删除数据库记录。
Microsoft Entity Framework是一个对象关系映射(O/RM)工具,它能你让自动从数据库生成数据访问层。Entity Framework能够使你免于手工编写冗长的数据访问类。
为了演示如何在ASP.NET MVC中使用Microsoft Entity Framework,我们将会创建一个简单的范例应用程序。我们将会创建一个Movie数据库应用程序,它允许你显示和编辑Movie数据库记录。
这篇教程假设你拥有Visual Studio 2008或者Visual Web Developer 2008及Service Pack1。为了使用Entity Framework,你需要使用Service Pack1。你可以从下面的地址下载Visual Studio 2008 Service Pack1或者含有Service Pack1的Visual Web Developer:
NOTE:在ASP.NET MVC和Microsoft Entity Framework之间没有什么必然的联系。在ASP.NET MVC中除了使用Entity Framework,你还有几个可选的方式。举个例子,你可以使用其他的O/RM工具,例如Microsoft LINQ to SQL,NHibernate或者SubSonic来创建你的MVC模型类。
1.创建Movie范例数据库
Movie数据库应用程序使用叫做Movies的数据库表格,它包含下面的列:
列名 | 数据类型 | 允许Null | 是否主键 |
Id | int | False | True |
Title | nvarchar(100) | False | False |
Director | nvarchar(100) | False | False |
你可以使用下面步骤将这个表添加到ASP.NET MVC项目中:
- 右键点击“解决方案浏览器”中的App_Data文件夹,并且选择菜单项“添加”,“新建项”。
- 在“添加新项(Add New Item)”对话框,选择“SQL Server Database”,将数据库命名为MoviesDB.mdf,并且点击“添加(Add)”按钮。
- 双击MoviesDB.mdf文件,打开“服务器资源管理器/数据库资源管理器”窗口。
- 展开MoviesDB.mdf数据库连接,右键点击“表”文件夹,并且选择菜单选项“添加新表(Add New Table)”。
- 在表设计器中,添加Id、Title和Director列。
- 点击“保存(Save)”按钮(它有一个软盘的图标)将新表保存为Movies。
在你创建好Movies数据库表之后,你应该为表中添加一些范例数据。右键点击Movies表,并且选择菜单项“显示表数据(Show Table Data)”。你可以向显示的网格中输入一些虚构的电影数据。
2.创建ADO.NET实体数据模型
为了使用Entity Framework,你需要创建一个实体数据模型(Entity Data Model)。你可以利用Visual Studio实体数据模型向导(Entity Data Model Wizard)来自动从数据库中生成一个实体数据模型。
按照下面的步骤:
- 右键点击“解决方案浏览器”窗口中的Models文件夹,并且选择菜单项,“添加(Add)”,“新建项(New Item)”。
- 在“添加新项(Add New Item)”对话框中,选择Data分类(如图1)。
- 选择ADO.NET Entity Data Model模板,将实体数据模型命名为MoviesDBModel.edmx,并且点击“添加”按钮。点击“添加”按钮将会运行数据模型向导。
- 在“选择模型内容(Choose Model Contents)”步骤,选择“从数据库生成(Generate from a database)”选项,并且点击“下一步(Next)”按钮(如图2)。
- 在“选择数据连接(Choose Your Data Conncetion)”步骤,选择MoviesDB.mdf数据库连接,输入实体的连接设置名MoviesDBEntities,并且点击“下一步”按钮(如图3)。
- 在“选择你的数据库对象(Choose Your Database Object)”步骤,选择Movie数据库表,并且点击“完成”按钮(如图4)。
在你完成了这些步骤以后,将会打开“ADO.NET实体数据模型设计器(实体设计器)”。
图1 - 创建一个新的实体数据模型
图2 - 选择模型内容步骤
图3 - 选择数据连接
图4 - 选择你的数据库对象
3.修改ADO.NET实体数据模型
在创建好实体数据模型以后,你可以利用实体设计器(如图5)来修改模型。通过双击“解决方案浏览器”中Models文件夹中的MoviesDBModel.edmx文件,你可以在任何时候打开实体设计器。
图5 - ADO.NET 实体数据模型设计器
举个例子,你可以使用“实体设计器”来更改“实体模型数据向导”生成的类名。向导创建了一个叫做Movies的新的数据访问类。换言之,Wizard对这个类的命名与数据库中的表名完全一致。因为我们将会使用这个类来代表特定的Movie实例,我们应该将这个类由Movies重命名为Movie。
如果你想要重命名实体类,你可以在实体设计器的类名上双击,并且输入一个新的名字(如图6)。或者,你可以在实体设计器中选择一个实体,然后在属性窗口中修改实体类的名字。
图6 - 更改一个实体名
记得在做出修改后点击“保存”按钮来保存你的“实体数据模型”。在幕后,实体设计器会生成一系列的C#类。通过从“解决方案资源管理器”窗口打开MoviesDBModel.Designer.cs文件,你可以查看这些类。
NOTE:不要在Designer.cs文件中修改代码,因为在下次使用实体设计器时,你的变更将会被覆盖。如果你想要扩展定义在Designer.cs中的实体类的功能,那么你可以在单独的文件中创建部分类。
4.使用Entity Framework选择数据库记录
让我们通过创建一个显示movie记录列表的页面来开始构建我们的Movie数据库应用程序。代码1中的Home控制器发布了一个名为Index()的动作。通过使用Entity Framework,Index()动作返回了来自Movie数据库表的所有movie记录。
代码清单1 - ControllersHomeController.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 Entity Framework生成的数据库实体。_db字段是一个MoviesDBEntities类的实例,该实例由“实体设计器”生成。
NOTE:为了在Home控制器中使用MoviesDBEntites类,你必须引入MovieEntityApp.Models命名空间。
在Index()动作中使用了_db字段,用于获取Movies数据库表中的记录。表达式_db.MovieSet代表了所有来自Movies数据库表的记录。ToList()方法用于将movies记录集转换为一个Movie对象的泛型集合(List<Movie>)。
movie记录在LINQ to Entities的帮助下获得。代码1中的Index()动作使用了LINQ方法语法(method syntax)来获取数据库的记录集。如果你愿意,你也可以使用LINQ查询语法(query syntax)。下面两行语句完成了同样的事情:
ViewData.Model = _db.MovieSet.ToList();
ViewData.Model = (from m in _db.MovieSet select m).ToList();
使用你最有感觉的任意一种LINQ语法――方法语法或者查询语法。这两种方法在性能上没有任何区别――唯一的区别是风格。
代码清单2中的视图用于显示movie记录。
代码清单2 - ViewsHomeIndex.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循环,它遍历了每一个movie记录,并且显示了movie记录的Title和Director属性的值。注意到在每个记录旁边显示了Edit和Delete链接。除此以外,Add Movie链接显示在视图的底部(如图7)。
图7 - Index 视图
Index视图是一个类型化视图(typed view)。Index视图包含了一个<%@ Page %>指示符,其中含有一个Inherits属性,它将Model属性强制转换为了一个Movie对象的强类型泛型列表集合(List<Movie>)。
5.使用Entity Framework插入数据库记录
你可以使用Entity Framework轻松地将新纪录插入到数据库表中。代码清单3包含了两个添加到Home控制器类中的新动作,你可以使用它们来将新纪录插入到Movie数据库表中。
代码清单3 - ControllersHomeController.cs(Add方法)
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()动作简单地返回了一个视图。这个视图包含了一个用于添加新movie数据库记录的表单(如图8)。当你提交表单时,将会调用第二个Add()动作。
注意到第二个Add()动作使用AcceptVerbs特性进行了修饰。这个动作只有在执行HTTP POST操作的时候才会被调用。换言之,这个动作只有在提交一个HTML表单的时候会被调用。
第二个Add()动作在ASP.NET MVC TryUpdateModel()方法的帮助下创建了一个Entity Framework Movie类的新实例。TryUpdateModel()方法接受传递给Add()方法的FormCollection的字段,并且将这些HTML表单字段的值赋值给Movie类。
NOTE:使用Entity Frmaework时,当用TryUpdateModel或者UpdateModel方法更新一个实体类的属性时,你必须提供一个属性的“白名单”。
接下来,Add()动作执行了一些简单的表单验证。该动作验证了Title和Director属性都有值。如果出现一个验证错误,那么一个验证错误消息将会添加到ModelState。
如果没有验证错误,那么在Entity Framework的帮助下,一个新的movie记录将会添加到Movies数据库表。新的记录使用下面两行代码添加到数据库中:
_db.AddToMovieSet(movieToAdd);
_db.SaveChanges();
代码的第一行将新的Movie实体添加到由Entity Framework所追踪的movies集中。代码的第二行将所有对Movies的更改保存到底层的数据库中。
图8 - Add 视图
6.使用Entity Framework更新数据库记录
你几乎可以按照与我们刚才插入一个新数据库记录相同的办法来使用Entity Framework编辑一条数据库记录。代码清单4包含了两个新的控制器动作,叫做Edit()。第一个Edit()动作返回了一个HTML表单,用于编辑一条movie记录。第二个Edit()动作试图更新数据库。
代码清单4 - ControllersHomeController.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()动作开始时从数据库中获取一条与要编辑的movie的Id相匹配的Movie记录。下面的LINQ to Entities语句获取了匹配这一特定Id的第一条数据库记录。
var movieToUpdate = _db.MovieSet.First(m => m.Id == id);
接下来,TryUpdateModel()方法用于将HTML表单域的值赋给movie实体的属性。注意到提供了一个白名单,用于指定更新哪些字段。
下一步,执行了一些简单的校验来验证Movie的Title和Director属性都有值。如果任何一个属性缺少值,那么一个校验错误消息将会添加到ModelState,并且ModelState.IsValid将会返回false值。
最后,如果没有校验错误,那么通过调用SaveChanges()方法,底层的Movies数据库表将会更新。
当编辑数据库记录时,你需要向执行数据库更新的控制器动作传递要进行更新的记录的Id。否则,控制器动作将无法知道更新底层数据库的哪一个记录。代码清单5中的Edit视图,含有一个隐藏的表单域,它代表了将要编辑的数据库记录的Id。
代码清单5 - ViewsHomeEdit.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>
7.使用Entity Framework删除数据库记录
在这篇教程中我们所需解决的最后一个数据库操作,就是删除数据库记录了。你可以使用代码清单6中的控制器动作来删除一个特定的数据库记录。
代码清单6 - ControllersHomeController.cs(删除操作)
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()动作首先获得一个Movie实体,该实体与传递给动作的Id相匹配。接下来,通过调用DeleteObject()方法和随后的SaveChanges()方法,Movie从数据库中删除掉了。最终,用户被重定向到了Index视图。
8.总结
本篇教程的目的是演示如何利用ASP.NET MVC和Microsoft Entity Framework来创建数据库驱动的Web应用程序。你学习到了如何创建应用程序,允许你进行选择、插入、更新和删除数据库记录。
首先,我们讨论了如何使用实体数据模型向导(Entity Data Model Wizard)从Visual Studio中生成一个实体数据模型。接下来,你学习了如何使用LINQ to Entities来从一个数据库表中获取一系列数据库记录。最后,我们使用了Entity Framework来插入、更新和删除数据库记录。
Asp.Net MVC 模型(使用LINQ to SQL创建Model类) - Part.2
这篇教程的目的是解释一种为ASP.NET MVC应用程序创建模型类的方法。在这篇教程中,你会学习到如何利用Microsoft LINQ to SQL创建模型类并执行数据库访问。
在这篇教程中,我们创建了一个基本的Movie数据库应用程序。我们尽可能地用最快速和最简单的方法创建Movie数据库应用程序作为开始。我们直接从控制器动作中执行了所有的数据访问。
接下来,你会学习如何使用Repository模式。使用Repository模式需要更多的一点工作。然而,采用这个模式的优点是它允许你创建能够适应变化并且测试简单的应用程序。
1.什么是Model类
MVC模型包含了所有MVC视图或者MVC控制器没有包含的应用程序逻辑。特别地,一个MVC模型包含了所有的应用程序业务和数据访问逻辑。
你可以使用各种各样不同的技术来实现你的数据访问逻辑。举个例子,你可以使用Microsoft Entity Framework、NHibernate、Subsonic或者ADO.NET类来构建你的数据访问类。
在这篇教程中,我使用LINQ to SQL来查询和更新数据库。LINQ to SQL为你提供了一种与Microsoft SQL Server数据库进行交互的非常简单的方法。然而,理解ASP.NET MVC框架丝毫没有局限于LINQ to SQL是非常重要的。ASP.NET MVC与任何的数据访问技术都是兼容的。
2.创建一个Movie数据库
在这篇教程中,为了演示如何构建模型类――我们创建了一个简单的Movie数据库应用程序。第一步是创建一个新的数据库。在解决方案浏览器窗口的App_Data文件夹上点击右键,选择菜单项“添加(Add)”,“新建项(New Item)”。选择SQL Server Database模板,命名为MoviesDB.mdf,并且点击“添加(Add)”按钮(如图1)。
图1:添加一个新的SQL Server Database
在你创建这个新的数据库以后,可以通过在App_Data文件夹中双击MoviesDB.mdf文件来打开数据库。双击MoviesDB.mdf文件会打开“服务器资源管理器(Server Explorer)”窗口(如图2)。
当使用Visual Web Developer时,“服务器资源管理器”叫做“数据库资源管理器(Database Explorer)”。
图2:使用“服务器资源管理器”窗口
我们需要在数据库中添加一个表,这个表代表电影。右键点击Tables文件夹,并且选择菜单项“添加新表(Add New Table)”。选择这个菜单项会打开“表设计器(Table Designer)”(如图3)。
图3:表设计器
我们需要向我们的数据库表添加下面的列:
列名 | 数据类型 | 允许Null |
Id | Int | False |
Title | Nvarchar(200) | False |
Director | Nvarchar(50) | False |
你需要对Id列做两件特别的事情。首先,你需要通过在表设计器中选择列,并且点击钥匙图标,将Id列标识为主键列。当对数据库进行插入或者更新时,LINQ to SQL要求你指定主键列。
接下来,你需要通过将IsIdentity属性赋值为Yes值,来将Id列标记为Identity列(如图3)。每当你向表中添加一行新数据时,Identity列会自动地赋一个新的数字。
3.创建LINQ to SQL类
我们的MVC模型类将会包含LINQ to SQL类,这些LINQ to SQL类代表着tblMovie数据库表。创建LINQ to SQL最简单的方法就是右键点击Models文件夹,选择“添加(Add)”,“新建项(New Item)”,选择LINQ to SQL类模板,将类命名为Movie.dbml,并且点击“添加”按钮(如图4)。
图4:创建LINQ to SQL类
在我们创建好Movie LINQ to SQL 类之后,会立即出现“对象关系设计器(Object Relational Designer)”。你可以将数据库表从“服务器资源管理器(Server Explorer)”窗口中拖曳到“对象关系设计器”中,来创建代表着特定数据库表的LINQ to SQL类。我们需要添加tblMovie数据库表到“对象关系设计器”中(如图5)。
图5:使用“对象关系设计器”
默认情况下,“对象关系设计器”创建的类与你拖曳到设计器中的数据库表名完全相同。然而,我们不想管我们的类叫做tblMovie。因此,在设计器中点击类名,并且将类名改为Movie。
最后,记得点击“保存(Save)”按钮来保存LINQ to SQL类。否则,LINQ to SQL类将不会由“对象关系设计器”生成。
4.在控制器动作中使用LINQ to SQL
现在我们已经拥有了LINQ to SQL类,我们可以使用这些类从数据库中获取数据。在本节中,你会学习如何直接在控制器动作中使用LINQ to SQL类。我们将会在一个MVC视图中显示来自tblMovies数据库表中的电影列表。
首先,我们需要更改HomeController类。这个类可以在你应用程序中的Controllers文件夹中找到。修改这个类,使得它像代码清单1所示的那样。
代码清单1 - ControllersHomeController.cs
using System.Linq;
using System.Web.Mvc;
using MvcApplication1.Models;
namespace MvcApplication1.Controllers{
[HandleError]
public class HomeController : Controller {
public ActionResult Index(){
var dataContext = new MovieDataContext();
var movies = from m in dataContext.Movies
select m;
return View(movies);
}
}
}
代码清单1中的Index()动作使用了LINQ to SQL DataContext类(MovieDataContext)来代表MoviesDB数据库。MovieDataContext类由Visual Studio“对象关系设计器”生成。
Index()动作执行了一个对DataContext的LINQ查询,用于从tblMovies数据库表中获取所有的电影。电影列表被赋给了一个叫做movies的本地变量。最后,电影列表通过视图数据传递给了视图。
为了显示电影列表,我们接下来需要修改Index视图。你可以在ViewsHome文件夹下找到Index视图。更新Index视图,让它和代码清单2中的视图相同。
代码清单2 - ViewsHomeIndex.aspx
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="MvcApplication1.Views.Home.Index" %>
<%@ Import Namespace="MvcApplication1.Models" %>
<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
<ul>
<% foreach (Movie m in (IEnumerable)ViewData.Model)
{ %>
<li> <%= m.Title %> </li>
<% } %>
</ul>
</asp:Content>
注意到修改后的Index视图在其顶部包含一个<%@import namespace%>指示符。这个指示符引入了MvcApplication1.Models命名空间。为了处理model类,我们需要这个命名空间,尤其是――视图中的Movie类。
代码清单2中的视图包含一个foreach循环,它遍历了所有由ViewData.Model属性所代表的项。显示了每一个movie的Title属性的值。
注意到ViewData.Model属性被强制转换为了一个IEnumerable。为了遍历ViewData.Model的内容,这个是必需的。另一个选择是创建一个强类型的视图。当你创建一个强类型的视图时,你将ViewData.Model属性强制转换为视图的后置代码类中的特定类型。
如果你在修改了HomeController类和Index视图后运行应用程序,你将会获得一个空白页。你之所以获得一个空白页,是因为在tblMovies数据库表中没有movie记录。
为了向tblMovies数据库表中添加记录,右键点击“服务器资源管理器”窗口(在Visual Web Developer中叫做“数据库资源管理器”)中的tblMovies数据库表,并且选择菜单项“显示表格数据(Show Table Data)”。你可以使用所显示的网格来插入movies记录(如图6)。
图6:插入电影
在你向tblMovies表中添加了一些数据库记录以后,并且运行应用程序,你将会看到图7所示的页面。所有的movie数据库记录都显示在了项目符号列表中。
图7:使用Index视图显示电影
5.使用Repository模式
在前面一节中,我们直接在一个控制器动作中使用了LINQ to SQL。我们直接从Index()控制器动作中使用了MovieDataContext类。对于一个简单的应用程序来说,这没有什么问题。然而,当你需要构建更加复杂的应用程序时,直接在控制器类中处理LINQ to SQL会造成一些问题。
在控制器类中使用LINQ to SQL会使以后切换数据访问技术时出现困难。举个例子,你可能想将Microsoft LINQ to SQL切换为使用Microsoft Entity Framework,来作为你的数据访问技术。在这种情况下,你需要在应用程序中重写每一个访问数据库的控制器。
在控制器类中使用LINQ to SQL也使得为应用程序创建单元测试更为困难。通常,在执行单元测试时,你不需要与数据库进行交互。你想要使用单元测试来测试你的应用程序逻辑,而非你的数据库服务器。
为了构建更加适应未来变化以及更加易于测试的MVC应用程序,你应该考虑使用Repository模式。当你使用Repository模式时,你会创建一个独立的repository类,它包含了所有的数据访问逻辑。
当你创建repository类时,你创建了一个接口,该接口代表着所有由repository类所使用的方法。在你的控制器中,你针对接口编写代码,而不是针对repository。通过这种方式,你以后可以使用不同的数据访问技术来实现repository。
代码清单3中的接口命名为了IMovieRepository,并且它包含了一个方法,叫做ListAll()。
代码清单3 - ModelsIMovieRepository.cs
using System.Collections.Generic;
namespace MvcApplication1.Models{
public interface IMovieRepository {
IList<Movie> ListAll();
}
}
代码清单4中的repository类实现了IMovieRepository接口。注意到它包含了一个叫做ListAll()的方法,该方法与IMovieRepository接口所要求的方法相对应。
代码清单4 - ModelsMovieRepository.cs
using System.Collections.Generic;
using System.Linq;
namespace MvcApplication1.Models {
public class MovieRepository : IMovieRepository {
private MovieDataContext _dataContext;
public MovieRepository() {
_dataContext = new MovieDataContext();
}
#region IMovieRepository Members
public IList<Movie> ListAll() {
var movies = from m in _dataContext.Movies
select m;
return movies.ToList();
}
#endregion
}
}
最后,代码清单5中的MoviesController类使用了Repository模式。它不再直接使用LINQ to SQL类。
代码清单5 - ControllersMoviesController.cs
using System.Web.Mvc;
using MvcApplication1.Models;
namespace MvcApplication1.Controllers {
public class MoviesController : Controller {
private IMovieRepository _repository;
public MoviesController() : this(new MovieRepository()) { }
public MoviesController(IMovieRepository repository) {
_repository = repository;
}
public ActionResult Index() {
return View(_repository.ListAll());
}
}
}
注意到代码清单5中的MoviesController类有两个构造函数。第一个构造函数,无参数的构造函数,在你应用程序运行时调用。这个构造函数创建了一个MovieRepository类的实例,并把它传递给了第二个构造函数。
第二个构造函数只有一个参数:一个IMovieRepository参数。这个构造函数简单地将参数的值赋给了叫做_repository的类级字段。
MoviesController类利用了软件设计模式中称作依赖注入(Dependency Injection)的模式。特别地,它使用了构造函数依赖注入(Constructor Dependency Injection)。你可以通过阅读下面这篇由Martin Fowler所作的文章,来阅读更多关于这个模式的信息:
http://martinfowler.com/articles/injection.html
注意到MoviesController类中所有的代码(除了第一个构造函数)都与IMovieRepository接口进行交互,而不是实际的MovieRepository类。代码与一个抽象的接口交互,而不是与接口的具体实现交互。
如果你想要修改应用程序所使用的数据访问逻辑,那么你可以简单地用一个类实现IMovieRepository接口,该类使用不同的数据库访问技术。举个例子,你可以创建一个EntityFrameworkMovieRepository类,或者一个SubSonicMovieRepository类。因为控制器类针对接口编程,你可以向控制器类传递一个IMovieRepository的新实现,并且这个类将继续工作。
除此以外,如果你想要测试MoviesController类,那么你可以向HomeController传递一个伪movie Respository类。你可以使用一个实际上并没有访问数据库,但是包含了所有IMovieRepository接口所要求的方法的类来实现IMovieRepository。通过这种方式,你可以对MoviesController类进行单元测试,而不需要实际地访问一个真正的数据库。
6.小结
这篇教程的目的是演示如何利用Microsoft LINQ to SQL创建MVC模型类。我们解释了在ASP.NET MVC应用程序中显示数据库数据的两种策略。首先,我们直接在控制器动作中创建和使用了LINQ to SQL类。在控制器中使用LINQ to SQL类使你能够快速且容易地在MVC应用程序中显示数据库数据。
接下来,我们探索了一个稍微困难一点儿,但绝对是一个更好的途径来显示数据库数据。我们利用了Repository模式,并且将所有的数据库逻辑都放在了一个独立的repository类中。在我们的控制器中,我们编写的所有代码都是针对一个接口,而非一个实体类。Repository模式的优点是它允许我们轻松地在以后改变数据访问技术,并且允许我们容易地测试我们的控制器类。
Asp.Net MVC 视图(显示数据库数据表格) - Part.3
在这篇教程中,我示范了显示一系列数据库记录的两个方法。我演示了在一个HTML表格中格式化一系列数据库记录的两个方法。首先,我演示了如何直接在视图中格式化数据库记录。接下来,我示范了如何在格式化数据库记录时利用部分类。
1.1创建模型类
我们将要显示Movies数据库表中的一系列记录。Movies数据库表包含下面的列:
Column Name | Data Type | Allow Nulls |
Id | Int | False |
Title | Nvarchar(200) | False |
Director | NVarchar(50) | False |
DateReleased | DateTime | False |
为了表示Movies数据库表,我们将利用Linq to SQL作为我们的数据访问技术。换言之,我们将会使用LINQ to SQL来绑定我们的MVC模型类。
创建一系列LINQ to SQL类的最快办法就是利用Visual Studio Object Relational Designer(Visual Studio 对象关系设计器)。右键点击Models文件夹,选择“Add(添加)”,“New Item(新建项)”,选择Linq To Sql类模板,将这个类命名为Movie.dbml,并且点击Add按钮(如图1)。
图1:创建LINQ to SQL类
在你创建完Movie Linq to Sql 类以后,会立即出现对象关系设计器。你可以将数据库表从服务器浏览器(Server Explorer)窗口中拖曳到对象关系设计器中,以便创建代表着特定数据库表的Linq to Sql类。你需要将Movies数据库表添加到对象关系设计器中(如图2)。
图2:使用对象关系设计器
默认情况下,对象关系设计器将会试图创建一个类名,该类名是数据库表名的单数版本。换言之,如果你有一个叫做Customers的数据库表,那么对象关系设计器将会创建一个叫做Customer的类名。
通常,对象关系设计器非常适合完成这件事。不幸的是,对象关系设计器将数据库表名Movies转换为了Movy(很接近,但是错的)。通过在设计器中的类名上点击,并且将类名由Movy改为Movie,你可以很容易地修正这个问题。
最后,记得点击“Save(保存)”(软盘图标)按钮来保存LINQ to SQL类。否则的话,LINQ to SQL类将不会由对象关系设计器生成。
1.2 在控制器动作中使用LINQ to SQL
现在我们已经有了LINQ to SQL类,我们可以使用这些类从数据库获取数据。代码清单1中的控制器类使用LINQ to SQL类获取来自Movies数据库表的记录。
代码清单1 – ControllersHomeController.cs
using System.Linq;
using System.Web.Mvc;
using MvcApplication1.Models;
namespace MvcApplication1.Controllers{
[HandleError]
public class HomeController : Controller {
public ActionResult Index() {
var dataContext = new MovieDataContext();
var movies = from m in dataContext.Movies
select m;
return View(movies);
}
}
}
代码清单1中的Index()动作使用LINQ to SQL MovieDataContext类来获取来自数据库表中的电影。电影列表被传递给了Index视图,作为ViewData.Model属性的值。
1.3 在视图中进行格式化
格式一系列数据库记录最简单、但不一定是最好的办法,就是直接在视图中执行格式化。举个例子,代码清单2中的Index视图在一个HTML表格中呈现了movie数据库的记录。
代码清单2 – ViewsHomeIndex.aspx
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="MvcApplication1.Views.Home.Index" %>
<%@ Import Namespace="MvcApplication1.Models" %>
<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
<table>
<tr>
<th>Id</th><th>Title</th><th>Release Date</th>
</tr>
<% foreach (Movie m in (IEnumerable)ViewData.Model)
{ %>
<tr>
<td><%= m.Id %></td>
<td><%= Html.Encode(m.Title) %></td>
<td><%= m.DateReleased %></td>
</tr>
<% } %>
</table>
</asp:Content>
代码清单2中的视图包含了一个foreach循环,该循环遍历了movie记录集中的每一个记录。Movie的每一个属性值都显示在了各自的表格单元格中。表格的行由HTML <tr>标签创建,表格单元格由HTML <td>标签创建。
注意到Html.Encode()帮助方法用于在显示每个属性值之前对其进行编码。任何时候当你接受用户输入,并且将输入重新显示在网页上时,对输入进行编码以阻止JavaScript注入攻击都是很重要的。当你对显示HTML内容前对它进行编码漠不关心时,黑客便可以做一些恶毒且邪恶的事情,例如从你的网站用户中盗取私人数据。
当你运行应用程序,Index视图会呈现如图3所示的页面。
图3:使用HTML表格格式化了的数据库记录
图3中HTML表格的格式化并不那么令人兴奋。我们可以通过创建层叠样式表来改进HTML表格的外观。因为代码清单2中的视图是一个content视图,我们必须将层叠样式表添加到与content视图相关联的模板页中。这个模板页位于下面路径:
ViewsSharedSite.master
为了改进HTML表格的外观,我们可以将代码清单3中的样式表添加到模板页<head>的开闭标签之间。
代码清单3 – 层叠样式表
<style type="text/css">
table
{
border-collapse:collapse;
}
table td, table th
{
border: solid 1px black;
padding:10px;
}
</style>
代码清单3中的样式表将单元格之间的边框合并起来,并且添加了网格(gridlines)。在你将这个样式表添加到模板页之后,Index视图呈现出图4中的页面。
图4:使用了样式的HTML表格
1.4 在局部中格式化
除了在视图本身中执行所有的格式化以外,你可以使用局部页面(partial)作为一个模板来格式化每一个数据库记录。举个例子,代码清单4中的局部页面代表着对于一个特定movie数据库记录的格式化。
代码清单4 –ViewsMoviesMovieTemplate.ascx
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="MovieTemplate.ascx.cs" Inherits="MvcApplication1.Views.Movies.MovieTemplate" %>
<tr>
<td> <%=ViewData.Model.Id%></td>
<td> <%=Html.Encode(ViewData.Model.Title)%></td>
<td> <%=ViewData.Model.DateReleased.ToString("D")%></td>
</tr>
代码清单4中的模板将每个movie记录格式化为一个HTML表格行。模板应用到每一个数据库记录上。注意到ViewData.Model属性,位于局部页面中,代表着单个数据库记录,而不是所有的数据库记录集。
为了将ViewData.Model属性转换为Movie类的实例,你需要为这个局部页面创建一个代码后置类。代码清单5中的代码后置类指定了MovieTemplate部分类继承自一个泛型类,该泛型类将Movie作为它的类型参数。
代码清单5 - ViewsMoviesMovieTemplate.ascx.cs
using MvcApplication1.Models;
namespace MvcApplication1.Views.Movies
{
public partial class MovieTemplate : System.Web.Mvc.ViewUserControl<Movie>
{
}
}
MovieTemplate类继承自ViewUserControl<movie>类。因为MovieTemplate类继承自这个类,ViewData.Model属性自动转换为Movie。
代码清单6中的Index视图演示了如何在视图中使用MovieTemplate部分类。Html.RenderPartial()方法用于呈现MovieTemplate局部页面。
代码清单 6 – ViewsMoviesIndex.aspx
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="MvcApplication1.Views.Movies.Index" %>
<%@ Import Namespace="MvcApplication1.Models" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<table>
<tr>
<th>Id</th><th>Title</th><th>Release Date</th>
</tr>
<% foreach (Movie m in (IEnumerable)ViewData.Model)
{
Html.RenderPartial("MovieTemplate", m);
} %>
</table>
</asp:Content>
在代码清单6中,Html.RenderPartial()方法用于为每个Movie记录呈现MovieTemplate局部页面。两个参数传递给了RenderPartial()方法。第一个参数是将要呈现的局部页面的名称。和视图一样,默认情况下,局部页面必须位于ViewsControlName 文件夹或者是 ViewsShared文件夹。
第二个参数指定了传递给部分的视图数据。在局部页面内部,ViewData.Model属性将会代表一个特定的Movie记录。
还有一个重要的警告。与大多数其他帮助方法不同,Html.RenderPartial()方法并不会返回一个字符串。这意味着你不能像下面这样调用RenderPatial()方法:
<%= Html.RenderPartial("MovieTemplate", m) %>
相反,你应该这样调用这个方法:
<% Html.RenderPartial("MovieTemplate", m) %>
RenderPartial()方法完成了一些事情,但它不会表示出来。
1.5 小结
这篇教程的目的是演示如何在一个HTML表格中显示一系列的数据库记录。我们探索了格式化数据库记录的两个方法。首先,我们直接在一个视图中格式化数据库记录。接下来,我们使用一个局部页面作为模板来格式化每一个数据库记录。
摘自:http://www.cnblogs.com/JimmyZhang/archive/2009/04/18/1438703.html