Ray 的记录站

日常开发实践记录

0%

.Net 5.0 如何进行 Code First 开发

在 .Net 或 dotnet core 5.0 中, 数据库相关开发时, 通常可以分为 Code First 和 Database First 两种方式的开发, 本文先看看如何进行 Code First 开发, 即先定义数据模型, 通过模型生成数据表及对应关系.

Code First 的总体步骤

1 创建初始迁移

  1. 定义模型 Entity, 一般而言, 都是在 Domain 中定义.

  2. 需要用到 Microsoft.EntityFrameworkCore 包中的 DbContext, 引入即可.

  3. 定义 DbContext 子类, 一般而言, 都是在 Infrastructure 中定义.

  4. 设置连接字符串, 连接字符串的写法如下所示, 不同数据库写法不一:

    1
    2
    3
    "ConnectionStrings": {
    "Default": "Server=localhost,14331;User Id=sa;Password=xxx;"
    }

    关于连接字符串的写法, 详见这个网站.

    注: 上述这个连接字符串中信息不完整, 无法工作, 解决方案请看 1.3 节.

  5. Startup 中注入 DbContext, 由于使用 UseSqlServer, 故引入 Microsoft.EntityFrameworkCore.SqlServer 包, 然后写注入代码:

    1
    2
    3
    4
    5
    services.AddDbContext<DataContext>(builder =>
    {
    var connectionString = Configuration.GetConnectionString("Default");
    builder.UseSqlServer(connectionString: connectionString);
    });
  6. 数据迁移需要用到 Microsoft.EntityFrameworkCore.Design 包, 引入并创建初始化迁移:

    1
    dotnet ef migrations add InitialCreate -p src/Reactivities.Infrastructure -s src/Reactivities.Web

    其中 -p 参数指定 DbContext 所在的 lib, -s 用于指定 startup 工程.

    初始迁移创建后, 只是生成了用于迁移的若干命令, 需要执行迁移才能把改动同步到数据库.

初始迁移创建完毕后, 仅仅生成了数据迁移相关的代码, 并没有实际进行迁移. 要进行迁移有两种办法, 一种是在命令行通过 dotnet ef 相关命令, 一种是在代码中.

我们这次使用代码中执行迁移的方式, 即: 检查是否已执行了最新的迁移, 如果没有, 则执行. 这样可以保证每次程序启动都可以让数据库 schema 和代码同步.

2 代码中检查和执行迁移

迁移检查/执行的代码一般都添加到 Main 函数中. 先改造默认生成的 Main 内容, 改为如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
// 经过了 build 调用, 此时已经把整个 Startup 的服务等都注入好了.
// 此时只需要通过如下方式获取即可.
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
var logger = services.GetRequiredService<ILogger<Program>>();
try
{
var context = services.GetRequiredService<DataContext>();
// 获取到 context 之后, 进行迁移的检查和运行.
context.Database.Migrate();
logger.LogInformation("已执行迁移!");
}
catch (Exception ex)
{
logger.LogError(ex, "在迁移时发生错误!");
}
}
host.Run();
}

上述代码中由于要使用 DbContext 服务对象, 故通过特殊的注入方式获取它.

3 迁移代码执行后不符预期的处理

当执行了上述代码后, log 中给出”已执行迁移”的信息, 但数据库中没有生成对应内容. 需要看看这个是什么原因.

检查发现 SQL Server 的连接字符串必须要按照规范填写, 否则无法实现相应功能. 比如之前的连接字符串中没有 Database 字段, 故无法进行迁移. 所以将连接字符串修改为如下:

1
2
3
"ConnectionStrings": {
"Default": "Server=localhost,14331;Database=Reactivities;User Id=sa;Password=xxx;"
}

为了演示方便, 没有将用户名和密码使用安全存储保存, 但在生产环境下千万要使用安全存储, 而不能直接把用户名密码等敏感信息使用明文写到配置中.

4 指定测试数据

测试数据可以通过重写 OnModelCreating 方法, 在其中使用 HasData:

1
2
3
4
5
6
7
8
9
10
11
12
13
/// <summary>
/// 通过重写这个方法来进一步配置 Entity.
/// </summary>
/// <param name="modelBuilder"></param>
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Value>().HasData(
new Value { Id = 1, Name = "Helloworld"},
new Value { Id = 2, Name = "Helloworld"},
new Value { Id = 3, Name = "Helloworld"},
new Value { Id = 4, Name = "Helloworld"}
);
}

有了这些代码后, 添加一个新的迁移:

1
dotnet ef migrations add SeedValues -p src/Reactivities.Infrastructure -s src/Reactivities.Web

再次运行工程即可将这个迁移的内容同步到数据库了. (如果没有写迁移执行代码, 则还可以使用命令行来手动执行迁移).