在MVC3的示例MvcMusicStore中,数据访问和模型这一块采用的是ADO.NET Entity Framework 4.0技术。
并且在里面使用了Code Frist技术。Code Frist是一种通过编写实体代码来逆向的创建数据库的一种技术。这种方式可以让你一开始就关注在编码上面,而不是关注在数据库或建模上面。这种编程方式非常适合于领域驱动开发(Domain-driven Development 缩写为DDD)。至于数据库如何访问,性能如何完全不需要我们编码人员操心。并且在编码的时候可以充分的利用Linq与之结合,编码起来非常舒服。具体说明请参考MSDN。
其中主要用到了两个类,一个是DbSet,这个类表示为一个实体集合,你可以把它理解为对应数据库中的一个表。另一个是DbContext,提供一系列针对于数据库的操作,包含有很多的实体集合,你可以把它理解为对应为数据库。
就像平常一样,我们可以编写一个普通的实体类,里面就标注几个属性而已,这是非常简单的编码。我这里编好了一个类Room。代码如下:
1 public class Room
2 {
3 /// <summary>
4 /// 主键房间序列号
5 /// key特性标记说明该属性将来对应数据库表中的主键
6 /// Column特性指定列的一些特性,这里指定列名叫RoomID
7 /// </summary>
8 [Key]
9 [Column(Name = "RoomID")]
10 public int RoomID { get; set; }
11
12 /// <summary>
13 /// TypeID类别编号,
14 /// ForeignKey特性说明这个属性是外键关联到RoomType表的主键的。
15 /// </summary>
16 [ForeignKey("TypeID")]
17 public int TypeID { get; set; }
18
19 /// <summary>
20 /// StringLength特性限定字符串最大的长度
21 /// </summary>
22 [StringLength(50)]
23 [Column(Name = "Number")]
24 public string Number { get; set; }
25
26 [Column(Name = "BedNumber")]
27 public int BedNumber { get; set; }
28
29 [StringLength(255)]
30 [Column(Name = "Description")]
31 public string Description { get; set; }
32
33 [StringLength(50)]
34 [Column(Name = "State")]
35 public string State { get; set; }
36
37 [Column(Name = "GuestNumber")]
38 public int GuestNumber { get; set; }
39
40 /// <summary>
41 /// RoomType类,将来可以通过它来关联到本Room所外键联系的RoomType
42 /// </summary>
43 public virtual RoomType RoomType { get; set; }
44 }
其中有些字段有特性说明,具体请仔细查看代码中的注释说明。
另外一个与Room类有关系的类是RoomType类,它是描述房间的类别。具体代码如下:
1 public class RoomType
2 {
3 /// <summary>
4 /// 主键
5 /// 房间类别编号
6 /// </summary>
7 [Key]
8 [DisplayName("房间类别编号")]
9 [Column(Name="TypeID")]
10 public int TypeID { get; set; }
11
12 [DisplayName("房间类别名称")]
13 [StringLength(50)]
14 [Column(Name = "TypeName")]
15 public string TypeName { get; set; }
16
17 [DisplayName("该类别价格")]
18 [Range(0.01,10000.00,ErrorMessage="价格必须在0.01到10000.00之间!")]
19 [Column(Name = "TypePrice")]
20 public decimal TypePrice { get; set; }
21
22
23 [DisplayName("是否可以加床")]
24 [Column(Name = "IsAddBed")]
25 public string IsAddBed { get; set; }
26
27 /// <summary>
28 /// Range特性说明这个属性的取值范围
29 /// </summary>
30 [DisplayName("加床价格")]
31 [Range(0.01, 10000.00, ErrorMessage = "价格必须在0.01到10000.00之间!")]
32 [Column(Name = "AddBedPrice")]
33 public decimal AddBedPrice { get; set; }
34
35 [DisplayName("备注")]
36 [Column(Name = "Remark")]
37 public string Remark { get; set; }
38
39 /// <summary>
40 /// 该类别所关联的房间信息集合
41 /// </summary>
42 public virtual List<Room> Rooms { get; set; }
43 }
这两个实体之间是有关系的,关系如下图所示:
为了能很好的描述好将来生成出来的数据库,还需要一个类。HotelManageEntities,该类继承自DbContext。具体代码如下:
1 public class HotelManageEntities:DbContext
2 {
3 public DbSet<Room> Room { get; set; }
4
5 public DbSet<RoomType> RoomType { get; set; }
6 }
该类非常简单,但是一定要注意在描述这两个属性的时候不能用复数形式,因为它会在进行逆向生成数据库表的时候自动加上复数形式。
至此为止,Entity Framework 4.0 的Code Frist技术就可以通过上面的代码给你生成好数据库以及对应实体模型的数据库表格。下面来做个界面测试一下,采用MVC3 Razor模板。
控制器代码如下:
1 /// <summary>
2 /// 呈现Room信息列表
3 /// </summary>
4 /// <returns></returns>
5 public ActionResult Index()
6 {
7 var rooms = hotelDB.Room.ToList();
8 return View(rooms);
9 }
10
11 /// <summary>
12 /// 呈现第一条Room的类别名称
13 /// </summary>
14 /// <returns></returns>
15 public ActionResult Test()
16 {
17 var rt = hotelDB.Room.First().RoomType.TypeName;
18 ViewBag.TypeName = rt;
19 return View();
20 }
Index Action对应的View代码如下(自动生成,没有做修改):
1 @model IEnumerable<HotelManageWeb.Models.Room>
2
3 @{
4 ViewBag.Title = "Index";
5 Layout = "~/Views/Shared/_Layout.cshtml";
6 }
7
8 <h2>Index</h2>
9
10 <p>
11 @Html.ActionLink("Create New", "Create")
12 </p>
13 <table>
14 <tr>
15 <th></th>
16 <th>
17 Number
18 </th>
19 <th>
20 BedNumber
21 </th>
22 <th>
23 Description
24 </th>
25 <th>
26 State
27 </th>
28 <th>
29 GuestNumber
30 </th>
31 </tr>
32
33 @foreach (var item in Model) {
34 <tr>
35 <td>
36 @Html.ActionLink("Edit", "Edit", new { id=item.RoomID }) |
37 @Html.ActionLink("Details", "Details", new { id=item.RoomID }) |
38 @Html.ActionLink("Delete", "Delete", new { id=item.RoomID })
39 </td>
40 <td>
41 @item.Number
42 </td>
43 <td>
44 @item.BedNumber
45 </td>
46 <td>
47 @item.Description
48 </td>
49 <td>
50 @item.State
51 </td>
52 <td>
53 @item.GuestNumber
54 </td>
55 </tr>
56 }
57
58 </table>
运行出来的效果如图:
Test Action对应的View界面代码如下:
1 @{
2 ViewBag.Title = "Test";
3 Layout = "~/Views/Shared/_Layout.cshtml";
4 }
5
6 <h2>Test</h2>
7
8 <p>Frist Room Type Name:@ViewBag.TypeName</p>
运行出来的效果如图:
总体上来说,整个代码非常简单,确实是如此,如果我们不想关注数据库和模型的话,这种编程方式给DDD带了很大的便利。
其中我也测试了一下,如果我已经有了数据库,现在要通过这种编码方式来提取和操作该数据库中的数据的话,是可行的。但是一定要注意在编写实体类的时候,数据库中的字段要和这个类中一一对应并区分大小写。实体类的命名也要注意别写成复数形式,数据库的表要复数形式,不然对应不上。这种情况就存在一些问题,可能和数据库中的表的名字对应不上的情况,这种情况我到官方网站上找了很多资料暂时没有找到很好的解决办法。期待在正式版本的时候有提供解决办法。
顺便说一句:今天貌似微软发布 VS2010 的SP1补丁。SP1补丁在MSDN的订阅上面有了是在3月8号发布的,但是我没有权限下载。找到微软下载中心,SP1补丁的说明已经有了,但是下载链接还没有。。。郁闷。。。