作者:里克·安德森
添加管理员控制器
在本部分中,我们将添加一个 Web API 控制器,该控制器支持对产品执行 CRUD(创建、读取、更新和删除)操作。 控制器将使用 Entity Framework 与数据库层通信。 只有管理员才能使用此控制器。 客户将通过另一个控制器访问产品。
在解决方案资源管理器中,右键单击“控制器”文件夹。 选择 “添加 ”,然后选择 “控制器”。
在 “添加控制器 ”对话框中,将控制器 AdminController命名为 。 在 “模板”下,选择“使用 Entity Framework 执行读/写操作的 API 控制器”。 在 Model 类下,选择“Product(ProductStore.Models)”。 在 “数据上下文”下,选择“<新建数据上下文>”。
注释
如果 Model 类 下拉列表未显示任何模型类,请确保编译项目。 实体框架使用反射,因此需要编译的程序集。
选择“<新建数据上下文>”将打开 “新建数据上下文 ”对话框。 命名数据上下文 ProductStore.Models.OrdersContext。
单击“ 确定 ”以消除 “新建数据上下文 ”对话框。 在 “添加控制器 ”对话框中,单击“ 添加”。
以下是被添加到项目中的内容:
- 一个命名为
OrdersContext的类派生自DbContext。 此类在 POCO 模型和数据库之间提供了连接。 - 名为 .. 的 Web API 控制器
AdminController。 此控制器支持执行 CRUD 操作于Product实例。 它使用该OrdersContext类与 Entity Framework 通信。 - Web.config 文件中的新数据库连接字符串。
打开OrdersContext.cs文件。 请注意,构造函数指定数据库连接字符串的名称。 此名称是指已添加到 Web.config的连接字符串。
public OrdersContext() : base("name=OrdersContext")
向 OrdersContext 类添加以下属性:
public DbSet<Order> Orders { get; set; }
public DbSet<OrderDetail> OrderDetails { get; set; }
DbSet 表示可以查询的一组实体。 下面是该 OrdersContext 类的完整列表:
public class OrdersContext : DbContext
{
public OrdersContext() : base("name=OrdersContext")
{
}
public DbSet<Order> Orders { get; set; }
public DbSet<OrderDetail> OrderDetails { get; set; }
public DbSet<Product> Products { get; set; }
}
该 AdminController 类定义实现基本 CRUD 功能的五种方法。 每个方法对应于客户端可以调用的 URI:
| 控制器方法 | 说明 | URI | HTTP 方法 |
|---|---|---|---|
| GetProducts | 获取所有产品。 | api/products | GET |
| GetProduct | 按 ID 查找产品。 | api/products/id | GET |
| PutProduct | 更新产品。 | api/products/id | 置入 |
| PostProduct | 创建新产品。 | api/products | POST |
| 删除产品 | 删除产品。 | api/products/id | 删除 |
每个方法调用 OrdersContext 查询数据库。 可以修改集合的 PUT、POST 和 DELETE 方法调用 db.SaveChanges 来将更改持久化保存到数据库。 控制器是按 HTTP 请求创建的,然后释放,因此需要在方法返回之前保留更改。
添加数据库初始化器
Entity Framework 具有一项很好的功能,可用于在启动时填充数据库,并在模型发生更改时自动重新创建数据库。 此功能在开发期间非常有用,因为即使更改模型,也始终具有一些测试数据。
在解决方案资源管理器中,右键单击 Models 文件夹并创建名为 OrdersContextInitializer 的新类。 粘贴以下实现:
namespace ProductStore.Models
{
using System;
using System.Collections.Generic;
using System.Data.Entity;
public class OrdersContextInitializer : DropCreateDatabaseIfModelChanges<OrdersContext>
{
protected override void Seed(OrdersContext context)
{
var products = new List<Product>()
{
new Product() { Name = "Tomato Soup", Price = 1.39M, ActualCost = .99M },
new Product() { Name = "Hammer", Price = 16.99M, ActualCost = 10 },
new Product() { Name = "Yo yo", Price = 6.99M, ActualCost = 2.05M }
};
products.ForEach(p => context.Products.Add(p));
context.SaveChanges();
var order = new Order() { Customer = "Bob" };
var od = new List<OrderDetail>()
{
new OrderDetail() { Product = products[0], Quantity = 2, Order = order},
new OrderDetail() { Product = products[1], Quantity = 4, Order = order }
};
context.Orders.Add(order);
od.ForEach(o => context.OrderDetails.Add(o));
context.SaveChanges();
}
}
}
通过继承自 DropCreateDatabaseIfModelChanges 类,我们告诉 Entity Framework 在修改模型类时删除数据库。 实体框架创建(或重新创建)数据库时,它会调用 Seed 方法来填充表。 我们使用 Seed 方法添加一些示例产品以及示例订单。
此功能非常适合测试,但不要在生产环境中使用 DropCreateDatabaseIfModelChanges 类,因为如果有人更改模型类,可能会丢失数据。
接下来,打开 Global.asax 并将以下代码添加到 Application_Start 方法:
System.Data.Entity.Database.SetInitializer(
new ProductStore.Models.OrdersContextInitializer());
向控制器发送请求
此时,我们尚未编写任何客户端代码,但可以使用 Web 浏览器或 HTTP 调试工具(如 Fiddler)调用 Web API。 在 Visual Studio 中,按 F5 开始调试。 您的 Web 浏览器将打开到http://localhost:*portnum*/,其中portnum 是某个端口号。
将 HTTP 请求发送到“http://localhost:*portnum*/api/admin。 第一个请求可能会很慢,因为 Entity Framework 需要创建并初始化数据库。 响应应类似于以下内容:
HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Mon, 18 Jun 2012 04:30:33 GMT
X-AspNet-Version: 4.0.30319
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Content-Type: application/json; charset=utf-8
Content-Length: 175
Connection: Close
[{"Id":1,"Name":"Tomato Soup","Price":1.39,"ActualCost":0.99},{"Id":2,"Name":"Hammer",
"Price":16.99,"ActualCost":10.00},{"Id":3,"Name":"Yo yo","Price":6.99,"ActualCost":
2.05}]