• 结合使用数据库和最小 API、Entity Framework Core 和 ASP.NET Core


    了解如何将数据库添加到最小 API 应用程序。

    简介

    基于 ASP.NET Core 生成的最小 API 可以使用 Entity Framework (EF) Core 轻松地与大量数据库集成。

    将了解如何使用 EF Core 将数据持久保存到内存数据库,然后再保存到 SQLite。 还将了解如何使用 EF Core 来查询数据库。

    向最小 API 应用程序添加数据库支持。

    什么是Entity Framework Core?

    大多数重要的 Web 应用程序都需要对数据可靠地运行创建、读取、更新和删除 (CRUD) 操作。 它们还需要在应用程序重启期间保留这些更改。 尽管有各种选项可用于在 .NET 应用程序中永久保留数据,但 Entity Framework (EF) Core 是一个用户友好型解决方案,非常适合许多 .NET 应用程序。

    了解EF Core

    EF Core 是 .NET 应用程序的轻型、可扩展、开源和跨平台的数据访问技术。

    EF Core 可以用作对象关系映射器:

    • 使 .NET 开发人员能够使用 .NET 对象处理数据库。
    • 无需再像通常那样编写大部分数据访问代码。

    EF Core 支持大量常见数据库,包括 SQLite、MySQL、PostgreSQL、Oracle 和 Microsoft SQL Server。

    模型

    使用 EF Core 时,数据访问是通过使用模型来执行的。 模型由实体类和表示数据库会话的上下文对象构成。 上下文对象允许查询并保存数据。

    实体类

    在此场景中,将实现一个比萨饼存储管理 API,因此你将使用 Pizza 实体类。 存储中的比萨饼具有名称和说明。 它们还需要 ID,以便 API 和数据库识别它们。 你将在应用程序中使用的 Pizza 实体类可识别比萨饼:

    1. namespace PizzaStore.Models
    2. {
    3. public class Pizza
    4. {
    5. public int Id { get; set; }
    6. public string? Name { get; set; }
    7. public string? Description { get; set; }
    8. }
    9. }

    上下文类

    此应用程序只有一个实体类,但大多数应用程序将有多个实体类。 上下文类负责查询数据并将其保存到实体类,以及用于创建和管理数据库连接。

    使用EF Core执行CRUD操作

    配置 EF Core 后,可以使用它对实体类执行 CRUD 操作。 然后,可以针对 C# 类进行开发,并将数据库操作委托给上下文类。 数据库提供程序反过来将其转换为特定于数据库的查询语言。 例如,关系数据库的 SQL。 即使上下文中已存在结果中返回的实体,也始终对数据库执行查询。

    查询数据

    上下文对象公开每个实体类型的集合类。 在前面的示例中,上下文类将 Pizza 对象的集合公开为 Pizzas。 假设有一个上下文类实例,则可以在数据库中查询所有比萨饼:

    var pizzas = await db.Pizzas.ToListAsync();

    插入数据

    可以使用相同的上下文对象插入新比萨饼:

    1. await db.pizzas.AddAsync(
    2. new Pizza { ID = 1, Name = "Pepperoni", Description = "The classic pepperoni pizza" });

    删除数据

    删除操作很简单。 它们只需要删除项的 ID:

    1. var pizza = await db.pizzas.FindAsync(id);
    2. if (pizza is null)
    3. {
    4. //Handle error
    5. }
    6. db.pizzas.Remove(pizza);

    更新数据

    同样,可以更新现有比萨饼:

    1. int id = 1;
    2. var updatepizza = new Pizza { Name = "Pineapple", Description = "Ummmm?" })
    3. var pizza = await db.pizzas.FindAsync(id);
    4. if (pizza is null)
    5. {
    6. //Handle error
    7. }
    8. pizza.Item = updatepizza.Item;
    9. pizza.IsComplete = updatepizza.IsComplete;
    10. await db.SaveChangesAsync();

    使用EF Core内存数据库

    EF Core 包含可用于测试应用程序的内存数据库提供程序。 内存数据库提供程序对于测试和开发非常有用,但不应在生产中使用。 在接下来的单元中,你将使用内存数据库提供程序来创建数据库并对其执行 CRUD 操作。

    将EF Core添加到最小API

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

    dotnet --list-sdks

    将显示类似于下面的输出:

    1. 3.1.100 [C:\program files\dotnet\sdk]
    2. 5.0.100 [C:\program files\dotnet\sdk]
    3. 6.0.100 [C:\program files\dotnet\sdk]

    确保列出了以 6 开头的版本。 

    设置项目

    首先,需要创建一个项目。 已安装 .NET 6,现已准备就绪。 将数据持久性添加到比萨饼管理 API。

    通过运行 dotnet new 创建 Web API:

    dotnet new web -o PizzaStore -f net6.0

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

    cd PizzaStore

    安装 Swashbuckle 包:

    dotnet add package Swashbuckle.AspNetCore --version 6.2.3

    创建 Pizza.cs 文件并在其中提供以下内容:

    1. namespace PizzaStore.Models
    2. {
    3. public class Pizza
    4. {
    5. public int Id { get; set; }
    6. public string? Name { get; set; }
    7. public string? Description { get; set; }
    8. }
    9. }

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

    打开 Program.cs,并添加代码: 

    1. using Microsoft.OpenApi.Models;
    2. var builder = WebApplication.CreateBuilder(args);
    3. builder.Services.AddEndpointsApiExplorer();
    4. builder.Services.AddSwaggerGen(c =>
    5. {
    6. c.SwaggerDoc("v1", new OpenApiInfo {
    7. Title = "PizzaStore API",
    8. Description = "Making the Pizzas you love",
    9. Version = "v1" });
    10. });
    11. var app = builder.Build();
    12. app.UseSwagger();
    13. app.UseSwaggerUI(c =>
    14. {
    15. c.SwaggerEndpoint("/swagger/v1/swagger.json", "PizzaStore API V1");
    16. });
    17. app.MapGet("/", () => "Hello World!");
    18. app.Run();

    Visual Studio Code 可能会提示你添加资产以调试项目。 单击对话框中的“Yes”。

    将EF Core添加到项目

    若要将项存储在待办事项列表中,请安装 EntityFrameworkCore.InMemory 包。

    在终端窗口中,输入以下代码以添加 EF Core InMemory 包:

    dotnet add package Microsoft.EntityFrameworkCore.InMemory --version 6.0

    1. PS C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\ASP.NET\PizzaStore> dotnet add package Microsoft.EntityFrameworkCore.InMemory --version 6.0
    2. 正在确定要还原的项目…
    3. Writing C:\Users\a-xiaobodou\AppData\Local\Temp\tmp2762.tmp
    4. info : X.509 certificate chain validation will use the default trust store selected by .NET.
    5. info : 正在将包“Microsoft.EntityFrameworkCore.InMemory”的 PackageReference 添加到项目“C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\ASP.NET\PizzaStore\PizzaStore.csproj”。
    6. info : 正在还原 C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\ASP.NET\PizzaStore\PizzaStore.csproj 的包...
    7. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore.inmemory/index.json
    8. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore.inmemory/index.json 923 毫秒
    9. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore.inmemory/6.0.0/microsoft.entityframeworkcore.inmemory.6.0.0.nupkg
    10. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore.inmemory/6.0.0/microsoft.entityframeworkcore.inmemory.6.0.0.nupkg 76 毫秒
    11. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore/index.json
    12. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore/index.json 291 毫秒
    13. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore/6.0.0/microsoft.entityframeworkcore.6.0.0.nupkg
    14. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore/6.0.0/microsoft.entityframeworkcore.6.0.0.nupkg 68 毫秒
    15. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore.abstractions/index.json
    16. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore.analyzers/index.json
    17. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.extensions.caching.memory/index.json
    18. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.extensions.dependencyinjection/index.json
    19. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.extensions.logging/index.json
    20. info : GET https://api.nuget.org/v3-flatcontainer/system.collections.immutable/index.json
    21. info : GET https://api.nuget.org/v3-flatcontainer/system.diagnostics.diagnosticsource/index.json
    22. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore.abstractions/index.json 283 毫秒
    23. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore.abstractions/6.0.0/microsoft.entityframeworkcore.abstractions.6.0.0.nupkg
    24. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore.abstractions/6.0.0/microsoft.entityframeworkcore.abstractions.6.0.0.nupkg 80 毫秒
    25. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore.analyzers/index.json 576 毫秒
    26. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore.analyzers/6.0.0/microsoft.entityframeworkcore.analyzers.6.0.0.nupkg
    27. info : OK https://api.nuget.org/v3-flatcontainer/system.collections.immutable/index.json 563 毫秒
    28. info : OK https://api.nuget.org/v3-flatcontainer/system.diagnostics.diagnosticsource/index.json 558 毫秒
    29. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.extensions.caching.memory/index.json 590 毫秒
    30. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.extensions.logging/index.json 579 毫秒
    31. info : GET https://api.nuget.org/v3-flatcontainer/system.collections.immutable/6.0.0/system.collections.immutable.6.0.0.nupkg
    32. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.extensions.dependencyinjection/index.json 597 毫秒
    33. info : GET https://api.nuget.org/v3-flatcontainer/system.diagnostics.diagnosticsource/6.0.0/system.diagnostics.diagnosticsource.6.0.0.nupkg
    34. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.extensions.caching.memory/6.0.0/microsoft.extensions.caching.memory.6.0.0.nupkg
    35. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.extensions.logging/6.0.0/microsoft.extensions.logging.6.0.0.nupkg
    36. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.extensions.dependencyinjection/6.0.0/microsoft.extensions.dependencyinjection.6.0.0.nupkg
    37. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore.analyzers/6.0.0/microsoft.entityframeworkcore.analyzers.6.0.0.nupkg 77 毫秒
    38. info : OK https://api.nuget.org/v3-flatcontainer/system.collections.immutable/6.0.0/system.collections.immutable.6.0.0.nupkg 73 毫秒
    39. info : OK https://api.nuget.org/v3-flatcontainer/system.diagnostics.diagnosticsource/6.0.0/system.diagnostics.diagnosticsource.6.0.0.nupkg 71 毫秒
    40. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.extensions.caching.memory/6.0.0/microsoft.extensions.caching.memory.6.0.0.nupkg 69 毫秒
    41. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.extensions.logging/6.0.0/microsoft.extensions.logging.6.0.0.nupkg 69 毫秒
    42. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.extensions.dependencyinjection/6.0.0/microsoft.extensions.dependencyinjection.6.0.0.nupkg 68 毫秒
    43. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.extensions.dependencyinjection.abstractions/index.json
    44. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.extensions.logging.abstractions/index.json
    45. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.extensions.caching.abstractions/index.json
    46. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.extensions.options/index.json
    47. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.extensions.primitives/index.json
    48. info : GET https://api.nuget.org/v3-flatcontainer/system.runtime.compilerservices.unsafe/index.json
    49. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.extensions.dependencyinjection.abstractions/index.json 276 毫秒
    50. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.extensions.dependencyinjection.abstractions/6.0.0/microsoft.extensions.dependencyinjection.abstractions.6.0.0.nupkg
    51. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.extensions.options/index.json 277 毫秒
    52. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.extensions.logging.abstractions/index.json 283 毫秒
    53. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.extensions.options/6.0.0/microsoft.extensions.options.6.0.0.nupkg
    54. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.extensions.caching.abstractions/index.json 292 毫秒
    55. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.extensions.logging.abstractions/6.0.0/microsoft.extensions.logging.abstractions.6.0.0.nupkg
    56. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.extensions.primitives/index.json 308 毫秒
    57. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.extensions.caching.abstractions/6.0.0/microsoft.extensions.caching.abstractions.6.0.0.nupkg
    58. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.extensions.primitives/6.0.0/microsoft.extensions.primitives.6.0.0.nupkg
    59. info : OK https://api.nuget.org/v3-flatcontainer/system.runtime.compilerservices.unsafe/index.json 286 毫秒
    60. info : GET https://api.nuget.org/v3-flatcontainer/system.runtime.compilerservices.unsafe/6.0.0/system.runtime.compilerservices.unsafe.6.0.0.nupkg
    61. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.extensions.dependencyinjection.abstractions/6.0.0/microsoft.extensions.dependencyinjection.abstractions.6.0.0.nupkg 76 毫秒
    62. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.extensions.options/6.0.0/microsoft.extensions.options.6.0.0.nupkg 72 毫秒
    63. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.extensions.logging.abstractions/6.0.0/microsoft.extensions.logging.abstractions.6.0.0.nupkg 71 毫秒
    64. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.extensions.caching.abstractions/6.0.0/microsoft.extensions.caching.abstractions.6.0.0.nupkg 70 毫秒
    65. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.extensions.primitives/6.0.0/microsoft.extensions.primitives.6.0.0.nupkg 70 毫秒
    66. info : OK https://api.nuget.org/v3-flatcontainer/system.runtime.compilerservices.unsafe/6.0.0/system.runtime.compilerservices.unsafe.6.0.0.nupkg 74 毫秒
    67. info : 已通过内容哈希 xlzi2IYREJH3/m6+lUrQlujzX8wDitm4QGnUu6kUXTQAWPuZY8i+ticFJbzfqaetLA6KR/rO6Ew/HuYD+bxifg== 从 https://api.nuget.org/v3/index.json 安装 Microsoft.Extensions.DependencyInjection.Abstractions 6.0.0 。
    68. info : 已通过内容哈希 9+PnzmQFfEFNR9J2aDTfJGGupShHjOuGw4VUv+JB044biSHrnmCIMD+mJHmb2H7YryrfBEXDurxQ47gJZdCKNQ== 从 https://api.nuget.org/v3/index.json 安装 Microsoft.Extensions.Primitives 6.0.0 。
    69. info : 已通过内容哈希 /iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg== 从 https://api.nuget.org/v3/index.json 安装 System.Runtime.CompilerServices.Unsafe 6.0.0 。
    70. info : 已通过内容哈希 bcz5sSFJbganH0+YrfvIjJDIcKNW7TL07C4d1eTmXy/wOt52iz4LVogJb6pazs7W0+74j0YpXFErvp++Aq5Bsw== 从 https://api.nuget.org/v3/index.json 安装 Microsoft.Extensions.Caching.Abstractions 6.0.0 。
    71. info : 已通过内容哈希 l4zZJ1WU2hqpQQHXz1rvC3etVZN+2DLmQMO79FhOTZHMn8tDRr+WU287sbomD0BETlmKDn0ygUgVy9k5xkkJdA== 从 https://api.nuget.org/v3/index.json 安装 System.Collections.Immutable 6.0.0 。
    72. info : 已通过内容哈希 eIbyj40QDg1NDz0HBW0S5f3wrLVnKWnDJ/JtZ+yJDFnDj90VoPuoPmFkeaXrtu+0cKm5GRAwoDf+dBWXK0TUdg== 从 https://api.nuget.org/v3/index.json 安装 Microsoft.Extensions.Logging 6.0.0 。
    73. info : 已通过内容哈希 WJmphvCn0wue9AX+Wvqj3XZ3ehNi9oyYBFNLtHVNvKqZrcimXBOqLo5RNf1fJWYSLWhOia/vzG4JtkAeZxZ8FQ== 从 https://api.nuget.org/v3/index.json 安装 Microsoft.EntityFrameworkCore.InMemory 6.0.0 。
    74. info : 已通过内容哈希 BqWBL05PUDKwPwLeQCJdc2R4cIUycXV9UmuSjYfux2fcgyet8I2eYnOWlA7NgsDwRVcxW26vxvNQ0wuc8UAcLA== 从 https://api.nuget.org/v3/index.json 安装 Microsoft.EntityFrameworkCore.Analyzers 6.0.0 。
    75. info : 已通过内容哈希 frQDfv0rl209cKm1lnwTgFPzNigy2EKk1BS3uAvHvlBVKe5cymGyHO+Sj+NLv5VF/AhHsqPIUUwya5oV4CHMUw== 从 https://api.nuget.org/v3/index.json 安装 System.Diagnostics.DiagnosticSource 6.0.0 。
    76. info : 已通过内容哈希 k6PWQMuoBDGGHOQTtyois2u4AwyVcIwL2LaSLlTZQm2CYcJ1pxbt6jfAnpWmzENA/wfrYRI/X9DTLoUkE4AsLw== 从 https://api.nuget.org/v3/index.json 安装 Microsoft.Extensions.DependencyInjection 6.0.0 。
    77. info : 已通过内容哈希 MrMLWEw4JsZdkVci0MkkGj+fSjZrXnm3m6UNuIEwytiAAIZPvJs3iPpnzfK4qM7np82W374voYm96q7QCdL0ow== 从 https://api.nuget.org/v3/index.json 安装 Microsoft.EntityFrameworkCore.Abstractions 6.0.0 。
    78. info : 已通过内容哈希 dzXN0+V1AyjOe2xcJ86Qbo233KHuLEY0njf/P2Kw8SfJU+d45HNS2ctJdnEnrWbM9Ye2eFgaC5Mj9otRMU6IsQ== 从 https://api.nuget.org/v3/index.json 安装 Microsoft.Extensions.Options 6.0.0 。
    79. info : 已通过内容哈希 Ve3BlCzhAlVp5IgO3+8dacAhZk1A0GlIlFNkAcfR2TfAibLKWIt5DhVJZfu4YtW+XZ89OjYf/agMcgjDtPxdGA== 从 https://api.nuget.org/v3/index.json 安装 Microsoft.Extensions.Caching.Memory 6.0.0 。
    80. info : 已通过内容哈希 /HggWBbTwy8TgebGSX5DBZ24ndhzi93sHUBDvP1IxbZD7FDokYzdAr6+vbWGjw2XAfR2EJ1sfKUotpjHnFWPxA== 从 https://api.nuget.org/v3/index.json 安装 Microsoft.Extensions.Logging.Abstractions 6.0.0 。
    81. info : 已通过内容哈希 BdHAtHzfQt3rltgSoYamSlHg2qawPtEDT677/bcSJlO8lQ/lj6XWlusM0TOt59O8Sbqm3hAC1a+4cEBxmv56pw== 从 https://api.nuget.org/v3/index.json 安装 Microsoft.EntityFrameworkCore 6.0.0 。
    82. info : 包“Microsoft.EntityFrameworkCore.InMemory”与项目“C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\ASP.NET\PizzaStore\PizzaStore.csproj”中指定的所有框架均兼容。
    83. info : 包“Microsoft.EntityFrameworkCore.InMemory”(版本为 6.0)的 PackageReference 已添加到文件“C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\ASP.NET\PizzaStore\PizzaStore.csproj”。
    84. info : 将资产文件写入磁盘。路径: C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\ASP.NET\PizzaStore\obj\project.assets.json
    85. log : 已还原 C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\ASP.NET\PizzaStore\PizzaStore.csproj (用时 7 sec)。
    86. PS C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\ASP.NET\PizzaStore>

    将 using Microsoft.EntityFrameworkCore; 添加到 Program.cs 和 Pizza.cs 文件的顶部。

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

    • 从数据库中的 Pizza 列表公开你的 Pizzas 属性。
    • 使用 UseInMemoryDatabase 连接内存数据库存储。 只要应用运行时,数据就会存储在此处。

    若要设置内存数据库,请将以下代码添加到 Pizza.cs 类底部(在最后的 } 的上方):

    1. class PizzaDb : DbContext
    2. {
    3. public PizzaDb(DbContextOptions options) : base(options) { }
    4. public DbSet Pizzas { get; set; }
    5. }

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

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

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

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

    返回项列表

    若要从比萨饼列表中的项列表中进行读取,请在调用 app.Run(); 之前添加以下代码以添加“/pizza”路由:

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

    运行应用程序

    通过调用 dotnet run 来运行应用。 此操作会生成应用,并将应用托管在 5000-5300 范围内的某个端口上。 HTTPS 会在 7000-7300 范围内为应用选择一个端口。

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

    dotnet run

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

    1. Building...
    2. info: Microsoft.Hosting.Lifetime[14]
    3. Now listening on: https://localhost:7200
    4. info: Microsoft.Hosting.Lifetime[14]
    5. Now listening on: http://localhost:5100
    6. info: Microsoft.Hosting.Lifetime[0]
    7. Application started. Press Ctrl+C to shut down.
    8. info: Microsoft.Hosting.Lifetime[0]
    9. Hosting environment: Development
    10. info: Microsoft.Hosting.Lifetime[0]
    11. Content root path: //PizzaStore

    在浏览器中转到 https://localhost:{PORT}/swagger。 选择 GET /pizzas 按钮,你会看到列表在 Response body 下为空。

    创建新项

    让我们将新任务 POST 到你先前创建的 app.MapGet 下的比萨饼列表。

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

    测试API

    返回到 Swagger,此时应会看到 POST/pizza。 向比萨饼列表添加新项:

    选择“POST /pizza”。

    选择“试用”。

    将请求正文替换为以下内容:

    1. {
    2. "name": "Pepperoni",
    3. "description": "A classic pepperoni pizza"
    4. }

    选择“执行”。

    读取列表中的项

    读取列表中的项:

    选择“GET /pizzas”。
    选择“试用”。
    选择“执行”。
    Response body 将包含刚刚添加的项。

    1. [
    2. {
    3. "id": 1,
    4. "name": "Pepperoni",
    5. "description": "A classic pepperoni pizza"
    6. }
    7. ]

    若要根据 id GET 项目,请将代码添加到前面创建的 app.MapPost 路由下。

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

    若要查看此内容,可以访问 https://localhost:{PORT}/pizza/1 或使用 Swagger UI。 由于使用的是内存数据库,在重启应用程序后不会列出前面创建的比萨饼,因此需要再次输入。

    更新项

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

    1. app.MapPut("/pizza/{id}", async (PizzaDb db, Pizza updatepizza, int id) =>
    2. {
    3. var pizza = await db.Pizzas.FindAsync(id);
    4. if (pizza is null) return Results.NotFound();
    5. pizza.Name = updatepizza.Name;
    6. pizza.Description = updatepizza.Description;
    7. await db.SaveChangesAsync();
    8. return Results.NoContent();
    9. });

    在 Swagger UI 中选择“PUT /pizza/{id}”。

    选择“试用”。

    在“ID”文本框中,输入 1。

    最后,更新 Request body。 粘贴以下 JSON 并将 name 更改为 Pineapple。

    1. {
    2. "id": 1,
    3. "name": "Pineapple",
    4. }

    选择“执行”。

    若要测试代码,请滚动回 GET /pizza/{id}。 比萨饼现在的名称为 Pineapple。

    ​​​​​​​

    删除项

    若要更新现有项目,请将代码添加到前面创建的 PUT /pizza/{id} 下:

    1. app.MapDelete("/pizza/{id}", async (PizzaDb db, int id) =>
    2. {
    3. var pizza = await db.Pizzas.FindAsync(id);
    4. if (pizza is null)
    5. {
    6. return Results.NotFound();
    7. }
    8. db.Pizzas.Remove(pizza);
    9. await db.SaveChangesAsync();
    10. return Results.Ok();
    11. });

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

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

    将SQLite数据库提供程序与EF Core结合使用

    学习了如何将数据持久保存到内存数据库。 将数据持久保存到内存数据库在开发中非常有用。 但是,由于在应用程序重启时所有数据都将丢失,因此它并不适合用于生产。 在生产环境中,应将数据持久保存到数据库,如 SQL Server、MySQL、PostgreSQL 或 SQLite。

    数据库提供程序从应用程序代码中抽象化数据库访问

    通过抽象层(如 Entity Framework (EF) Core)执行数据库访问的好处之一是,它将应用程序与数据库提供程序分离。 你可以更改数据库提供程序,而无需重写数据库访问代码。 你无法在不影响应用程序代码的情况下切换数据库提供程序,但更改会最小化并本地化。

    使用 EF Core 的相关优势在于,你可以重用代码、经验和数据访问库,以便与任何其他 EF Core 数据库提供程序一起使用。

    EF Core 当前支持超过 20 个数据库提供程序。


    添加新数据库提供程序的步骤

    通常,将使用以下步骤来实现新数据库提供程序:

    1. 将一个或多个 NuGet 包添加到项目中,以包含数据库提供程序。
    2. 配置数据库连接。
    3. 在 ASP.NET Core 服务中配置数据库提供程序。
    4. 执行数据库迁移。

    在此之前,已将数据保存在内存数据库中。 此数据库在开发应用程序时非常容易设置和使用,但数据不是持久的。 因此,在应用程序重启时数据将丢失。 在部署应用程序之前,需要将数据持久保存到数据库。

    将升级应用程序以使用关系数据库来存储数据。 将使用 SQLite 来存储数据。

    设置 SQLite 数据库

    完成以下部分以设置 SQLite 数据库。


    安装以下工具和包

    使用 .NET CLI 和 Visual Studio 包管理器 UI,安装下列包:

    • SQLite EF Core 数据库提供程序:可以通过名为数据库提供程序的插件库访问许多不同的数据库。 以下包是用于 Entity Framework (EF) Core 的 SQLite 数据库提供程序。
      dotnet add package Microsoft.EntityFrameworkCore.Sqlite --version 6.0
      1. PS C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\ASP.NET\PizzaStore> dotnet add package Microsoft.EntityFrameworkCore.Sqlite --version 6.0
      2. 正在确定要还原的项目…
      3. Writing C:\Users\a-xiaobodou\AppData\Local\Temp\tmp9CF1.tmp
      4. info : X.509 certificate chain validation will use the default trust store selected by .NET.
      5. info : 正在将包“Microsoft.EntityFrameworkCore.Sqlite”的 PackageReference 添加到项目“C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\ASP.NET\PizzaStore\PizzaStore.csproj”。
      6. info : 正在还原 C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\ASP.NET\PizzaStore\PizzaStore.csproj 的包...
      7. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore.sqlite/index.json
      8. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore.sqlite/index.json 906 毫秒
      9. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore.sqlite/6.0.0/microsoft.entityframeworkcore.sqlite.6.0.0.nupkg
      10. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore.sqlite/6.0.0/microsoft.entityframeworkcore.sqlite.6.0.0.nupkg 69 毫秒
      11. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore.sqlite.core/index.json
      12. info : GET https://api.nuget.org/v3-flatcontainer/sqlitepclraw.bundle_e_sqlite3/index.json
      13. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore.sqlite.core/index.json 280 毫秒
      14. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore.sqlite.core/6.0.0/microsoft.entityframeworkcore.sqlite.core.6.0.0.nupkg
      15. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore.sqlite.core/6.0.0/microsoft.entityframeworkcore.sqlite.core.6.0.0.nupkg 67 毫秒
      16. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore.relational/index.json
      17. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.data.sqlite.core/index.json
      18. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.extensions.dependencymodel/index.json
      19. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.extensions.dependencymodel/index.json 566 毫秒
      20. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.extensions.dependencymodel/6.0.0/microsoft.extensions.dependencymodel.6.0.0.nupkg
      21. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.extensions.dependencymodel/6.0.0/microsoft.extensions.dependencymodel.6.0.0.nupkg 71 毫秒
      22. info : OK https://api.nuget.org/v3-flatcontainer/sqlitepclraw.bundle_e_sqlite3/index.json 1215 毫秒
      23. info : GET https://api.nuget.org/v3-flatcontainer/sqlitepclraw.bundle_e_sqlite3/2.0.6/sqlitepclraw.bundle_e_sqlite3.2.0.6.nupkg
      24. info : GET https://api.nuget.org/v3-flatcontainer/system.text.encodings.web/index.json
      25. info : GET https://api.nuget.org/v3-flatcontainer/system.text.json/index.json
      26. info : GET https://api.nuget.org/v3-flatcontainer/system.buffers/index.json
      27. info : GET https://api.nuget.org/v3-flatcontainer/system.memory/index.json
      28. info : OK https://api.nuget.org/v3-flatcontainer/sqlitepclraw.bundle_e_sqlite3/2.0.6/sqlitepclraw.bundle_e_sqlite3.2.0.6.nupkg 72 毫秒
      29. info : GET https://api.nuget.org/v3-flatcontainer/sqlitepclraw.core/index.json
      30. info : GET https://api.nuget.org/v3-flatcontainer/sqlitepclraw.provider.e_sqlite3/index.json
      31. info : GET https://api.nuget.org/v3-flatcontainer/sqlitepclraw.lib.e_sqlite3/index.json
      32. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore.relational/index.json 924 毫秒
      33. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore.relational/6.0.0/microsoft.entityframeworkcore.relational.6.0.0.nupkg
      34. info : OK https://api.nuget.org/v3-flatcontainer/system.text.encodings.web/index.json 282 毫秒
      35. info : GET https://api.nuget.org/v3-flatcontainer/system.text.encodings.web/6.0.0/system.text.encodings.web.6.0.0.nupkg
      36. info : OK https://api.nuget.org/v3-flatcontainer/system.text.json/index.json 318 毫秒
      37. info : GET https://api.nuget.org/v3-flatcontainer/system.text.json/6.0.0/system.text.json.6.0.0.nupkg
      38. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.entityframeworkcore.relational/6.0.0/microsoft.entityframeworkcore.relational.6.0.0.nupkg 248 毫秒
      39. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.data.sqlite.core/index.json 1214 毫秒
      40. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.data.sqlite.core/6.0.0/microsoft.data.sqlite.core.6.0.0.nupkg
      41. info : OK https://api.nuget.org/v3-flatcontainer/system.buffers/index.json 455 毫秒
      42. info : GET https://api.nuget.org/v3-flatcontainer/system.buffers/4.5.1/system.buffers.4.5.1.nupkg
      43. info : OK https://api.nuget.org/v3-flatcontainer/system.text.json/6.0.0/system.text.json.6.0.0.nupkg 111 毫秒
      44. info : OK https://api.nuget.org/v3-flatcontainer/system.text.encodings.web/6.0.0/system.text.encodings.web.6.0.0.nupkg 200 毫秒
      45. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.data.sqlite.core/6.0.0/microsoft.data.sqlite.core.6.0.0.nupkg 66 毫秒
      46. info : OK https://api.nuget.org/v3-flatcontainer/system.buffers/4.5.1/system.buffers.4.5.1.nupkg 65 毫秒
      47. info : OK https://api.nuget.org/v3-flatcontainer/sqlitepclraw.lib.e_sqlite3/index.json 555 毫秒
      48. info : GET https://api.nuget.org/v3-flatcontainer/sqlitepclraw.lib.e_sqlite3/2.0.6/sqlitepclraw.lib.e_sqlite3.2.0.6.nupkg
      49. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.extensions.configuration.abstractions/index.json
      50. info : OK https://api.nuget.org/v3-flatcontainer/sqlitepclraw.lib.e_sqlite3/2.0.6/sqlitepclraw.lib.e_sqlite3.2.0.6.nupkg 66 毫秒
      51. info : OK https://api.nuget.org/v3-flatcontainer/system.memory/index.json 1187 毫秒
      52. info : GET https://api.nuget.org/v3-flatcontainer/system.memory/4.5.4/system.memory.4.5.4.nupkg
      53. info : OK https://api.nuget.org/v3-flatcontainer/sqlitepclraw.provider.e_sqlite3/index.json 1253 毫秒
      54. info : OK https://api.nuget.org/v3-flatcontainer/sqlitepclraw.core/index.json 1266 毫秒
      55. info : OK https://api.nuget.org/v3-flatcontainer/system.memory/4.5.4/system.memory.4.5.4.nupkg 123 毫秒
      56. info : GET https://api.nuget.org/v3-flatcontainer/sqlitepclraw.core/2.0.6/sqlitepclraw.core.2.0.6.nupkg
      57. info : GET https://api.nuget.org/v3-flatcontainer/sqlitepclraw.provider.e_sqlite3/2.0.6/sqlitepclraw.provider.e_sqlite3.2.0.6.nupkg
      58. info : OK https://api.nuget.org/v3-flatcontainer/sqlitepclraw.core/2.0.6/sqlitepclraw.core.2.0.6.nupkg 135 毫秒
      59. info : OK https://api.nuget.org/v3-flatcontainer/sqlitepclraw.provider.e_sqlite3/2.0.6/sqlitepclraw.provider.e_sqlite3.2.0.6.nupkg 141 毫秒
      60. info : GET https://api.nuget.org/v3-flatcontainer/system.memory/4.5.3/system.memory.4.5.3.nupkg
      61. info : OK https://api.nuget.org/v3-flatcontainer/system.memory/4.5.3/system.memory.4.5.3.nupkg 230 毫秒
      62. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.extensions.configuration.abstractions/index.json 1079 毫秒
      63. info : GET https://api.nuget.org/v3-flatcontainer/microsoft.extensions.configuration.abstractions/6.0.0/microsoft.extensions.configuration.abstractions.6.0.0.nupkg
      64. info : OK https://api.nuget.org/v3-flatcontainer/microsoft.extensions.configuration.abstractions/6.0.0/microsoft.extensions.configuration.abstractions.6.0.0.nupkg 69 毫秒
      65. info : 已通过内容哈希 Vh8n0dTvwXkCGur2WqQTITvk4BUO8i8h9ucSx3wwuaej3s2S6ZC0R7vqCTf9TfS/I4QkXO6g3W2YQIRFkOcijA== 从 https://api.nuget.org/v3/index.json 安装 SQLitePCLRaw.core 2.0.6 。
      66. info : 已通过内容哈希 cx55qNWk5JmUMZgMfGvfwodW2z/t3Kix7Fbso9BxCPnPVaiVm8k9C4QLjegqJVvuRAA7RZigMYAqeRZ9Q4fWWQ== 从 https://api.nuget.org/v3/index.json 安装 Microsoft.EntityFrameworkCore.Sqlite.Core 6.0.0 。
      67. info : 已通过内容哈希 qWzV9o+ZRWq+pGm+1dF+R7qTgTYoXvbyowRoBxQJGfqTpqDun2eteerjRQhq5PQ/14S+lqto3Ft4gYaRyl4rdQ== 从 https://api.nuget.org/v3/index.json 安装 Microsoft.Extensions.Configuration.Abstractions 6.0.0 。
      68. info : 已通过内容哈希 zssYqiaucyGArZfg74rJuzK0ewgZiidsRVrZTmP7JLNvK806gXg6PGA46XzoJGpNPPA5uRcumwvVp6YTYxtQ5w== 从 https://api.nuget.org/v3/index.json 安装 SQLitePCLRaw.bundle_e_sqlite3 2.0.6 。
      69. info : 已通过内容哈希 3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA== 从 https://api.nuget.org/v3/index.json 安装 System.Memory 4.5.3 。
      70. info : 已通过内容哈希 peXLJbhU+0clVBIPirihM1NoTBqw8ouBpcUsVMlcZ4k6fcL2hwgkctVB2Nt5VsbnOJcPspQL5xQK7QvLpxkMgg== 从 https://api.nuget.org/v3/index.json 安装 SQLitePCLRaw.provider.e_sqlite3 2.0.6 。
      71. info : 已通过内容哈希 TD5QHg98m3+QhgEV1YVoNMl5KtBw/4rjfxLHO0e/YV9bPUBDKntApP4xdrVtGgCeQZHVfC2EXIGsdpRNrr87Pg== 从 https://api.nuget.org/v3/index.json 安装 Microsoft.Extensions.DependencyModel 6.0.0 。
      72. info : 已通过内容哈希 X6MCFkzJOBkcgzT00Bh7SAqbLM2rPuHgCWMivSRiZ0VGVfgf/l8nwGDe9wYSSjXVdw95JUggvWOQLcNfbBFuLA== 从 https://api.nuget.org/v3/index.json 安装 Microsoft.Data.Sqlite.Core 6.0.0 。
      73. info : 已通过内容哈希 Vg8eB5Tawm1IFqj4TVK1czJX89rhFxJo9ELqc/Eiq0eXy13RK00eubyU6TJE6y+GQXjyV5gSfiewDUZjQgSE0w== 从 https://api.nuget.org/v3/index.json 安装 System.Text.Encodings.Web 6.0.0 。
      74. info : 已通过内容哈希 Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg== 从 https://api.nuget.org/v3/index.json 安装 System.Buffers 4.5.1 。
      75. info : 已通过内容哈希 1MbJTHS1lZ4bS4FmsJjnuGJOu88ZzTT2rLvrhW7Ygic+pC0NWA+3hgAen0HRdsocuQXCkUTdFn9yHJJhsijDXw== 从 https://api.nuget.org/v3/index.json 安装 System.Memory 4.5.4 。
      76. info : 已通过内容哈希 VwNbLaMpDD9s/tVmK/sivJsYoXdM3ARBjWMtFUXVExZ6AgZxPwSgILF2J4Y9CRvf/r6A0xitvFXQO6HPrZnwrg== 从 https://api.nuget.org/v3/index.json 安装 Microsoft.EntityFrameworkCore.Sqlite 6.0.0 。
      77. info : 已通过内容哈希 rTRzrSbkUXoCGijlT9O7oq7JfuaU1/+VFyfSBjADQuOsfa0FCrWeB8ybue5CDvO/D6uW0kvPvlKfY2kwxXOOdg== 从 https://api.nuget.org/v3/index.json 安装 Microsoft.EntityFrameworkCore.Relational 6.0.0 。
      78. info : 已通过内容哈希 zaJsHfESQvJ11vbXnNlkrR46IaMULk/gHxYsJphzSF+07kTjPHv+Oc14w6QEOfo3Q4hqLJgStUaYB9DBl0TmWg== 从 https://api.nuget.org/v3/index.json 安装 System.Text.Json 6.0.0 。
      79. info : 已通过内容哈希 xlstskMKalKQl0H2uLNe0viBM6fvAGLWqKZUQ3twX5y1tSOZKe0+EbXopQKYdbjJytNGI6y5WSKjpI+kVr2Ckg== 从 https://api.nuget.org/v3/index.json 安装 SQLitePCLRaw.lib.e_sqlite3 2.0.6 。
      80. info : 包“Microsoft.EntityFrameworkCore.Sqlite”与项目“C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\ASP.NET\PizzaStore\PizzaStore.csproj”中指定的所有框架均兼容。
      81. info : 包“Microsoft.EntityFrameworkCore.Sqlite”(版本为 6.0)的 PackageReference 已添加到文件“C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\ASP.NET\PizzaStore\PizzaStore.csproj”。
      82. info : 将资产文件写入磁盘。路径: C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\ASP.NET\PizzaStore\obj\project.assets.json
      83. log : 已还原 C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\ASP.NET\PizzaStore\PizzaStore.csproj (用时 6.69 sec)。
      84. PS C:\Users\a-xiaobodou\OneDrive - Microsoft\Projects\ASP.NET\PizzaStore>

    • EF Core 工具:EF Core 工具执行设计时开发任务。 例如,它们基于现有数据库创建迁移、应用迁移和生成模型代码。
      dotnet tool install --global dotnet-ef

    • Microsoft.EntityFrameworkCore.Design:包含 EF Core 用于创建数据库的所有设计时逻辑。
      dotnet add package Microsoft.EntityFrameworkCore.Design --version 6.0


    启用数据库创建

    若要启用数据库创建,需要完成两个步骤:

    1. 设置数据库连接字符串。
    2. 将数据模型迁移到 SQLite 数据库。


    设置数据库连接字符串

    在 Program.cs 的应用生成器 var builder = WebApplication.CreateBuilder(args); 下方,添加一个连接字符串。

    var connectionString = builder.Configuration.GetConnectionString("Pizzas") ?? "Data Source=Pizzas.db";

     
    将上下文添加到服务

    在 CRUD 部分,使用的是内存数据库。 现在,要将内存数据库替换为永久性数据库。

    将生成服务中的当前内存数据库实现 builder.Services.AddDbContext(options => options.UseInMemoryDatabase("items")); 替换为此处的 SQLite 数据库:

    builder.Services.AddSqlite(connectionString);


    迁移数据模型

    利用 EF Core 迁移工具,你现在可以开始首次迁移 InitialCreate。 在终端窗口中,运行 migrations 命令:

    dotnet ef migrations add InitialCreate

    EF Core 将在项目目录中创建一个名为“Migrations”的文件夹,该文件夹包含两个文件,其中包含表示数据库迁移的代码。


    创建数据库和架构

    完成迁移后,可以使用它来创建数据库和架构。

    在终端窗口中,运行以下 database update 命令,将迁移应用到数据库:

    dotnet ef database update

    你应在项目目录中看到新创建的 Pizzas.db 文件。

    运行和测试应用程序

    现在,已经有了一个后备数据库,更改将永久保留。

    若要测试应用程序,请在终端窗口中运行 dotnet run 命令,并在 Swagger UI 中与 API 交互。 可以使用 Ctrl+C 命令停止运行应用程序。 在 macOS 上使用 Cmd+C。 然后再次运行该应用程序,并验证更改是否仍然保留。

  • 相关阅读:
    结合protobuf和socket实现多进程通讯
    趋势安全软件卸载:如何不需要密码或忘记密码卸载Trend Micro OfficeScan Agent?
    4-5网络层-路由协议
    千兆以太网网络层 ARP 协议的原理与 FPGA 实现
    uni-app之android项目云打包
    【STM32】IWDG—独立看门狗
    【排序 + 优先队列 】数对组数问题
    微服务组件之Hystrix
    如何在数据库中存储小数:FLOAT、DECIMAL还是BIGINT?
    在 Android 上部署自定义 YOLOv8 教程
  • 原文地址:https://blog.csdn.net/DXB2021/article/details/126353439