冠军

思胜.NET 高级培训

导航

公告

统计

2011年11月13日 #

ASP.NET MVC 音乐商店 - 4. 数据访问

上一次,我们使用了模拟的数据从控制器发送到视图模板。现在,我们开始使用真正的数据库,在这个教程中,我们将指导如何使用 SQL Server Compact 版的数据库,它经常被称为 SQL CE, 来作为数据库引擎,SQL CE 是一个免费的,嵌入式的,基于文件的数据库系统,不需要任何的安装或者配置,很适合本地的开发使用。

注意:可能需要单独安装 SQL Server Compact 4.0 数据库以及 Entity Framework。在我的机器上,这两个软件都是单独安装的。

当然,你还可以使用熟悉的 SQL Server 数据库。

Microsoft SQL Server Compact 4.0

Microsoft SQL Server Compact 4.0 是一种免费的嵌入式数据库,也就是说,你不需要安装数据库系统。软件开发人员可以使用它来构建 ASP.NET 网站和 Windows 桌面应用程序。SQL Server Compact 4.0 的优点是:占用的空间小,支持在应用程序文件夹中专门部署其二进制文件,轻松地使用 Visual Studio 和 WebMatrix 进行应用程序开发,以及无缝地将架构和数据迁移到 SQL Server。

SQL Server Compact 4.0 安装文件的下载地址:http://www.microsoft.com/downloads/zh-cn/details.aspx?familyid=033cfb76-5382-44fb-bc7e-b3c8174832e2&displaylang=zh-cn

不过,你完全可以不使用这个数据库,还继续使用原来的 SQL Server, 在我的机器上,我不能直接使用服务器资源管理器来查看 SQL CE 4 的的数据。如果使用原来的 SQL Server 就不会有这个问题了。

ADO.NET Entity Framework 4.1

EF 4.1有哪些新玩新儿?

1. 首先当然是DbContext API,它是基于以前版本中的ObjectContext和其他一些类型抽象出的一个简单的API,针对常用开发场景和编程模式进行了优化。DbContext可以被于Database First, Model First, Code First三种开发模式。

2. Code First是基于Entity Framework的新的开发模式,原先只有Database First和Model First两种。Code First顾名思义,就是先用C#/VB.NET的类定义好你的领域模型,然后用这些类映射到现有的数据库或者产生新的数据库结构。Code First同样支持通过Data Annotations或fluent API进行定制化配置。

这里的数据访问就使用 Code First 完成,它会使你的数据访问惊人地简单。

关于ADO.NET Entity Framework 4.1,我以前翻译了一个系列,地址: http://www.cnblogs.com/haogj/archive/2011/05/06/2038965.html

ADO.NET Entity Framework 4.1 安装文件下载地址:http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=8363 

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

我们将使用包含在 ASP.NET MVC3 中的 Entity Framework (EF) 支持进行查询和更新数据库中的数据。EF 是一个灵活的进行数据访问的对象关系映射 API,允许开发人员使用面向对象的方式对数据库中的数据进行查询和更新。

Entity Framework 4 支持一种称为代码优先的开发模式,代码有限允许你通过编写简单的类来创建模型对象(也被称为 POCO, 简单的,老的 CLR 对象),然后通过类来创建数据。

注意,需要在你的项目中引用程序集 EntityFramework,在你安装 Entity Framework 的文件夹中可以找到这个程序集。

修改我们的模型类

我们将延后数据库的创建工作,在完成这个任务之前,我们先修改我们得模型类,增加我们需要的内容。

增加艺术家 Artist 类

我们的专辑将要关联到艺术家,所以,我们需要增加一个简单的类来描述艺术家,增加一个新的名为 Artist 的类。

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

 

更新现有的模型类

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 类

namespace MvcMusicStore.Models
{
public 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 文件夹

这一步并不必要,如果使用 SQL CE4,可以用来保存数据库文件,如果使用 SQL Server 则不一定需要。

我们在项目中增加 App_Data 文件夹用来保存数据库文件,App_Data 是一个 ASP.NET 中特殊的文件夹,已经被网站对其中数据地访问进行了安全限制,从项目的菜单中,选择增加 ASP.NET 文件夹,然后,选择 App_Data.

在 Web.config 中创建数据库连接串

我们需要在网站的配置文件中增加一些行,以便 Entity Framework 知道如何连接到我们的数据库,双击 Web.config 文件。

卷到文件的最后,然后增加一个 <connectionStrings> 的配置节,如何所示:

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

注意,这里数据库连接串的名称很重要,以后使用 EF Code-First 的时候,通过它来找到数据库,这里的链接串种使用了 Data Source=|DataDirectory|MvcMusicStore.sdf,这里的 DataDirectory 指的就是项目中的 App_Data 文件夹夹。

如果使用 SQL Server, 可以使用如下的链接串。注意 providerName 也要替换成 SQLServer 使用的提供器。

<!-- 数据库连接串的配置 -->
<connectionStrings>
<add name="MusicStoreEntities"
connectionString
="server=.\sqlexpress;database=musicstore;integrated security=true;"
providerName
="System.Data.SqlClient"/>
</connectionStrings>

 

增加上下文类

在模型文件夹上右键点击,然后,增加一个新的名为 MusicStoreEntities.cs 的文件。 需要注意的是,这个类的名称必须与数据库连接串的名称一致。

这个类将反映 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; }


public DbSet<Artist> Artists { get; set; }
}
}

 

注意,这里使用了 System.Data.Entity 命名空间。记得要 using 一下。

不需要其他的配置,特定的接口等等,通过扩展 DbContext 基类,我们得 MusicStoreEntities 类就可以处理我们对数据库的操作了,现在,我们就开始,先为我们的类增加一些属性来从数据库获取额外的信息。

增加我们的商店分类数据

对于 Code First 来说,我们首先定义模型,然后通过模型来创建数据库,甚至也不需要写 Insert 语句,我们可以通过标准的 C# 代码来创建表中的记录。

我们先通过一些种子数据通过 Entity Framework 为新创建的数据库增加一些数据。先创建我们的商店分类,这需要通过一个 Genres 的列表完成,还有专辑。在 MvcMusicStore-Asset.zip 文件中,已经包含了用来简单地创建数据的文件,有一个保存在 Code 文件夹中的类来完成。

在 Code 中的 Models 文件夹中,找到 SampleData.cs 文件,将它加入到 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 中定义一个字段来访问我们的 MusicStoreEneities 类的对象实例,它命名为 storeDB。

using MvcMusicStore.Models;

namespace MvcMusicStore.Controllers
{
public class StoreController : Controller
{
MusicStoreEntities storeDB = new MusicStoreEntities();

 

更新 Index Action 查询数据库

MusicStoreEntities 类通过 Entity Framework 提供了数据库中数据表的集合,更新一下 StoreController 的 Index Action 方法来获取全部的分类数据。我们原来使用硬编码的数据,现在,我们可以使用 Entity Framework 的 Generes 集合来取代它了。

对于 EF 的使用,我建议你了解一下 Repository 模式。

//
// GET: /Store/
public ActionResult Index()
{
var genres = storeDB.Genres.ToList();

return this.View( genres );
}

 

对于视图模板不需要任何修改,我们仍然返回同样的 StoreIndexViewModel 。

运行程序,访问 /Store 地址的时候,我们现在可以看到数据库中分类的列表。

  

使用数据库中的数据更新浏览和明细页面

当在首页通过 /Store/Browse?genre=[some-genre] 链接访问 Browse 这个 Action 的时候,我们需要通过流派的名称来获取相应的专辑,对于我们的音乐店来说,每个流派的名称是唯一的,可以通过 LINQ 中的 Single 扩展方法来获取查询结果中的唯一的流派对象。

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

 

Single 方法使用一个 Lambda 表达式作为参数,表示我们希望获取匹配指定值的单个流派对象,在上面的例子中,我们将会获得名为  Disco 的流派对象。

通过 EF ,在获得流派对象的同时,我们还可以获取流派相关的对象,例如属于这个流派的专辑集合,我们可以提前获取相关的专辑信息,这就需要我们修改一下上面的查询,包含专辑信息。通过 Include 方法可以指定我们希望获取的相关信息,这种方式非常有效,这样,我们就可以在一次数据访问中,既可以获取流派对象,也可以同时获取相关的专辑对象。

这样更新之后,我们的 Action 方法将会成为下面的样子。

// /Store/Browse?genre=DISCO
public ActionResult Browse( string genre )
{
var genreModel = storeDB.Genres.Include("Albums").Single(g => g.Name == genre);

return this.View(genreModel);
}

注意,在流派 Genre 的属性中有一个名为 Albums 的集合属性。

然后,我们可以更新一下 Store 的 Browse 视图来显示相应的专辑,打开视图模板,增加一个列表。

@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,现在就可以看到保存在数据库中的的专辑数据了。

同样,我们还可以修改一下 Details ,通过传递的参数来获取专辑对象。修改后的方法如下所示。

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

 

运行程序,访问 /Store/Details/1,应该可以看到下面的内容。

我们更新一下 Browse 视图,提供链接到明细页面的超级链接,这里,我们使用 ActionLink 方法,修改后的视图如下所示。

再次浏览 Browse 的时候,每个专辑应该已经成为了一个链接,如图所示:

 

posted @ 2011-11-13 22:43 冠军 阅读(5197) 评论(38) 编辑

转:Repository 资源库模式

这些内容来自 (英)Martin Fowler   的 《企业应用架构模式》。

协调领域和数据映射层,利用类似于集合的接口来访问领域对象。 

具有复杂领域模型的系统常常受益于一个层,比如由数据映射器提供的层,它分离了领域对象和数据库访问代码的细节。在这种系统中,有必要在集中了查询构造代码的映射层之上建立另外一个抽象层。当存在大量的领域类或者繁重的查询时,这样做就显得更重要。在这些特定情况下,增加该层可以使重复的查询逻辑最小化。

资源库协调领域和数据映射层,起到类似内存中领域对象集合的作用。客户对象以陈述的方式构建查询说明,并把它们提交给资源库以获取满足条件的对象。可以向资源库中增加对象,也可以从资源库中删除对象,就像这些对象来自一个简单的对象集合,并且由资源库封装的映射代码将根据实际情形执行相应的操作。从概念上来说,资源库封装了保存在数据存储中的对象集以及在这些对象上执行的操作,提供一个更加符合面向对象观点的持久层实现。资源库也支持在领域和数据映射层之间实现彻底分离和单向以来关系的目标。

 

运行机制

 

资源库是使用了本书中大量其他模式的一种高级模式。事实上,资源库看上去像面向对象数据库的一小块,从这个角度来说,它类似于查询对象,在此情况下开发小组往往会使用对象-关系映射工具而不是亲自创建它们。然而,如果开发小组已经采取了这一步,并创建了查询对象,则增加资源库功能就不难了。当和查询对象一起使用时,资源库不用增加很多操作就可以为对象-关系映射层添加很大程度的可用性。

不考虑隐藏在后台的所有机制,资源库表现为简单的查询接口。客户创建一个条件对象指定他们需要由查询返回的对象的特征。例如,要根据姓名来查找 Person 对象,首先创建一个条件对象,把每个单独条件设置成如:criteria.equals( Person.LAST_NAME, “Fowler”),及criteria.lik( Person.FIRST_NAME, ‘M’) 。然后调用repository.matching(criteria ) 返回一个领域对象的列表,该列表表示所有姓为 Fowler,名字已  M 开头的人。可以在一个抽象的资源库上定义各种类似于 matching( criteria ) 的便利方法;例如,当只需要一个匹配的对象时,soleMatch( criteria ) 可返回查找到的那个对象而不返回集合。其他常见的方法包括byObjectId( id ),它可以通过简单的调用 soleMatch 来实现。

对于使用资源库的代码而言,资源库看起来像一个简单的内存领域对象集合。领域对象本身通常不会直接存储在资源库中,这一事实并没有暴露给客户代码。当然,使用资源库的代码应该清楚,这个表面上的对象集合可能实际上映射为一个具有成百上千记录的产品表。在目录系统的 ProductRepository 上调用 all() 方法未必是一个好方法。

资源库用一个基于规约的对象选择方法来取代基于数据映射器类的特殊的查找器方法。这种方法与直接使用查询对象相比,后者的客户代码可能建立一个条件对象(规约模式的一个简单例子),在查询条件中直接提供 all() 函数,并执行查询。有了资源库,客户代码创建条件,然后把它们传递到资源库,由资源库选择其中和条件匹配的对象。从客户代码的角度来说,不存在查询“执行”的概念;但是要根据满足查询对象规约的条件来选择适当对象。这看上去或许只是术语上的差别,但是它阐明了对象与资源库进行交互的好处,这也是其概念威力的一个很大部分。

在外表之下,资源库把元数据映射和查询对象结合起来,自动由条件生成 SQL 代码。无论条件是否知道如何把自身增加到查询中,查询对象都知道怎样合并条件对象,或者由元数据映射自身控制交互是实现的细节。

资源库的对象源可能根本不是关系数据库,这也没有问题,资源库能顺利通过特定的策略对象取代数据映射部分。因为这个原因,资源库对存在多数据库方案或者领域对象源的系统十分有用。另外,在以排他方式使用内存对象的测试代码中,有望获得比较快的速度。

资源库可以成为一种改善代码(这种代码会广泛使用查询)可读性和清晰性的好机制。例如,一个以具有许多查询页面为特征的基于浏览器的系统需要一个简洁的机制来处理由 HttRequest 对象得到的查询结果。如果不能自动转换,该请求的处理程序代码通常能在不带来较多混乱的情况下把 HttpRequest 对象转换为条件对象;把条件提交给适当的资源库仅仅需要增加额外的一行或者两行代码。

 

使用时机

 

在需要领域对象类型和许多可能查询的大型系统中,资源库减少了用于处理所有要执行查询的代码总量。资源库改进了规约模式(这里以条件对象的形式),规约模式以纯面向对象的方式封装了要执行的查询。因此,可以删除所有对特例建立查询对象的代码。客户从来不比考虑 SQL,而仅仅根据对象来写代码。

然而,在多数据源的情况下将真正看到资源库的作用。例如,假设有时我们想使用简单的内存数据存储,通常是在为了获得较好性能而想完全在内存中运行单元测试的时候。没有数据库访问时,许多长德测试包运行的比较快。为单元测试创建固定的构件 ( fixture ) 同样比较简单,如果所做的只是构建一些领域对象并在建立时把它们放置在集合中,而不是保存在数据库中并在析构时删除它们。

当一个应用程序正常运行时,某些领域对象的确定类型应该一直被保存在内存中,对这种情况也可以考虑使用资源库。不变领域对象(那些不能被用户改变的对象)就是这样一个例子,这种对象一旦进入内存,就会一直保留在里面而且不会被再次查询。就像我们在本章后面将看到的,一个简单的资源库模式的扩展允许根据情况采用不同的查询策略。

另外一个可以使用资源库模式的例子是当把数据输入当作领域对象源使用的时候,比如,互联网上的一个 XML 流(或许使用 SOAP)可以作为一个源使用。一个 XMLFeed RepositoryStrategry 可能被实现,它从 feed 中读取输入并从 XML 中创建领域对象。

资源库模式的两个特点: 

行为类似内存中的集合

查询规约提交到资源库

posted @ 2011-11-13 00:11 冠军 阅读(1220) 评论(0) 编辑