练习 - 将 EF Core 添加到最小 API

已完成

你是公司的开发人员,你和你的公司都听说过新的最小 API。 你的经理要求你为其创建一个项目,以便你能够讨论是否在下一个项目上使用它。

注释

本模块使用 .NET CLI(命令行接口)和 Visual Studio Code 进行本地开发。 完成本模块后,你可以使用 Visual Studio (Windows)、Visual Studio for Mac (macOS) 来应用概念,或使用 Visual Studio Code(Windows、Linux 和 macOS)进行持续开发。

本模块使用 .NET 8.0 SDK。 通过在首选命令终端中运行以下命令,确保你已安装 .NET 8.0:

dotnet --list-sdks

将显示类似于以下示例的输出:

6.0.317 [C:\Program Files\dotnet\sdk]
7.0.401 [C:\Program Files\dotnet\sdk]
8.0.100 [C:\Program Files\dotnet\sdk]

确保列出了以 8 开头的版本。 如果未列出或找不到该命令, 请安装最新的 .NET 8.0 SDK

启动项目

首先,需要创建项目。 已安装 .NET 6 并已准备就绪。 在本单元中,你将向披萨管理 API 添加数据持久性。

  1. 在终端中,通过运行 dotnet new以下内容创建 Web API:

    dotnet new web -o PizzaStore -f net8.0
    

    应会看到 PizzaStore 目录。

  2. 输入以下命令转到 PizzaStore 目录:

    cd PizzaStore
    
  3. 安装 Swashbuckle 包:

    dotnet add package Swashbuckle.AspNetCore --version 6.5.0
    
  4. 在 Visual Studio Code 中打开项目。

  5. 使用 Visual Studio Code 在项目根目录中创建 Pizza.cs 文件,并为其提供以下内容:

    namespace PizzaStore.Models 
    {
        public class Pizza
        {
              public int Id { get; set; }
              public string? Name { get; set; }
              public string? Description { get; set; }
        }
    }
    

    前面的 Pizza 类是表示披萨的简单对象。 此代码是数据模型。 稍后,你将使用 Entity Framework (EF) Core 将此数据模型映射到数据库表。

  6. 打开 Program.cs 并添加突出显示的代码:

    using Microsoft.OpenApi.Models;
    
    var builder = WebApplication.CreateBuilder(args);
    
    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddSwaggerGen(c =>
    {
         c.SwaggerDoc("v1", new OpenApiInfo {
             Title = "PizzaStore API",
             Description = "Making the Pizzas you love",
             Version = "v1" });
    });
    
    var app = builder.Build();
    if (app.Environment.IsDevelopment())
    {
       app.UseSwagger();
       app.UseSwaggerUI(c =>
       {
          c.SwaggerEndpoint("/swagger/v1/swagger.json", "PizzaStore API V1");
       });
    }
    
    app.MapGet("/", () => "Hello World!");
    
    app.Run();
    

    Visual Studio Code 可能会提示你添加资产以调试项目。 在对话框中选择 Yes

将 EF Core 添加到项目

若要将项存储在 to-do 列表中,请安装包 EntityFrameworkCore.InMemory

  1. Ctrl+' 在 Visual Studio Code 中打开终端。 在新终端中,输入以下代码以添加 EF Core InMemory 包:

    dotnet add package Microsoft.EntityFrameworkCore.InMemory --version 8.0
    
  2. using Microsoft.EntityFrameworkCore;添加到Program.csPizza.cs文件的顶部。

    将 EF Core 添加到项目后,可以将代码连接到要保存和查询的数据。 若要执行此步骤,请创建一个 PizzaDb 类。 该 PizzaDb 类将执行以下任务:

    • Pizzas从数据库中的属性Pizza列表中公开属性。
    • 用于 UseInMemoryDatabase 连接内存中数据库存储。 只要应用正在运行,数据就存储在此处。
  3. 若要设置内存中数据库,请将以下代码添加到 Pizza.cs 文件底部(在最终 }文件上方)。 命名空间中有两个 PizzaStore.Models 类定义。

    class PizzaDb : DbContext
    {
        public PizzaDb(DbContextOptions options) : base(options) { }
        public DbSet<Pizza> Pizzas { get; set; } = null!;
    }
    

    DbContext 表示用于查询和保存数据库中实体实例的连接或会话。

  4. 添加到using PizzaStore.Models;Program.cs文件的顶部。

  5. Program.cs,在调用 AddSwaggerGen之前,添加以下代码:

    builder.Services.AddDbContext<PizzaDb>(options => options.UseInMemoryDatabase("items"));
    

返回项列表

  • 若要从披萨列表中的项目列表进行读取,请在调用上方添加以下代码以 app.Run(); 添加“/pizzas”路由:

    app.MapGet("/pizzas", async (PizzaDb db) => await db.Pizzas.ToListAsync());
    

运行应用程序

  1. 确保已保存所有更改。 通过在终端中调用 dotnet run 来运行应用。 此作将生成应用并将其托管在 5000-5300 的端口上。 HTTPS 将在 7000-7300 范围内为其选择端口。

    注释

    如果要覆盖随机端口选择行为,可以在 launchSettings.json 中设置要使用的端口。

    dotnet run
    

    下面是输出在终端中的情况:

    Building...
     info: Microsoft.Hosting.Lifetime[14]
           Now listening on: https://localhost:7200
     info: Microsoft.Hosting.Lifetime[14]
           Now listening on: http://localhost:5100
     info: Microsoft.Hosting.Lifetime[0]
           Application started. Press Ctrl+C to shut down.
     info: Microsoft.Hosting.Lifetime[0]
           Hosting environment: Development
     info: Microsoft.Hosting.Lifetime[0]
           Content root path: /<path>/PizzaStore
    
  2. 在浏览器中转到 https://localhost:{PORT}/swagger。 选择 GET /pizzas 按钮,然后 试用执行。 你将看到列表在下方 Response body为空。

  3. 在终端中,按 Ctrl+C 停止运行程序。

创建新项

让我们将代码添加到 POST 披萨列表的新项。 在 Program.cs中,在前面创建的代码下 app.MapGet 添加以下代码。

app.MapPost("/pizza", async (PizzaDb db, Pizza pizza) =>
{
    await db.Pizzas.AddAsync(pizza);
    await db.SaveChangesAsync();
    return Results.Created($"/pizza/{pizza.Id}", pizza);
});

测试 API

请确保已保存所有更改并再次运行应用。 返回到 Swagger UI,现在应会看到 POST/pizza。 若要向披萨列表添加新项目,请执行以下作:

  1. 选择 POST /pizza

  2. 选择试用

  3. 将请求正文替换为以下 JSON:

    {
        "name": "Pepperoni",
        "description": "A classic pepperoni pizza"
    }
    
  4. 选择“执行”。

若要读取列表中的项,

  1. 选择 GET /pizzas

  2. 选择试用

  3. 选择“执行”。

    Response body 包括刚刚添加的项。

    [
      {
        "id": 1,
        "name": "Pepperoni",
        "description": "A classic pepperoni pizza"
      }
    ]
    
  4. 在终端中按 Ctrl+C 停止运行应用。 对于本练习的其余部分,请根据需要停止并重启应用以测试更改。 请务必先保存所有更改 dotnet run

获取单个项

若要获取 id项,请在前面创建的路由下 app.MapPost 添加代码。

app.MapGet("/pizza/{id}", async (PizzaDb db, int id) => await db.Pizzas.FindAsync(id));

按 ID 测试 GET

若要测试此作,可以转到 https://localhost:{PORT}/pizza/1 或使用 Swagger UI。 由于使用的是内存中数据库,因此如果重新启动应用程序,则之前创建的披萨将不会列出。 因此,需要使用 POST作再次添加它。

更新一项内容

若要更新现有项,请在创建的路由下 GET /pizza/{id} 添加代码:

app.MapPut("/pizza/{id}", async (PizzaDb db, Pizza updatepizza, int id) =>
{
      var pizza = await db.Pizzas.FindAsync(id);
      if (pizza is null) return Results.NotFound();
      pizza.Name = updatepizza.Name;
      pizza.Description = updatepizza.Description;
      await db.SaveChangesAsync();
      return Results.NoContent();
});

测试 PUT

  1. 在 Swagger UI 中选择 PUT /pizza/{id}

  2. 选择试用

  3. ID 文本框中,输入 1

  4. 最后,更新 Request body。 粘贴以下 JSON 并更改为 namePineapple

    {
       "id": 1,
       "name": "Pineapple"
    }
    
  5. 选择“执行”。

若要测试代码,请向下滚动到 GET /pizza/{id}。 披萨现在有名字 Pineapple

删除项

若要删除现有项,请添加前面创建的代码 PUT /pizza/{id}

app.MapDelete("/pizza/{id}", async (PizzaDb db, int id) =>
{
   var pizza = await db.Pizzas.FindAsync(id);
   if (pizza is null)
   {
      return Results.NotFound();
   }
   db.Pizzas.Remove(pizza);
   await db.SaveChangesAsync();
   return Results.Ok();
});

测试 DELETE

现在,请尝试使用 Swagger 接口删除项。

在本单元中,你已将 EF Core 添加到现有的最小 API 应用程序,并使用内存中数据库来存储数据。 接下来,你将了解如何使用实际数据库来存储数据,以便在应用程序关闭之间保留。