Entity Framework Core 总结

.NET Core CLI

此种方法对于 ASP.NET Core 也可以使用,其实当执行命令 dotnet ef migrations 时,会启动所在程序集(Program.cs),和正常启动ASP.NET Core 一样,所以会依赖注入 MyDbContext等

1
2
3
4
5
6
7
8
9
10
11
# 全局安装 EF Core 工具
dotnet tool install --global dotnet-ef

# 安装 设计包,这是对项目运行命令所必需的
dotnet add package Microsoft.EntityFrameworkCore.Design

# migrations 命令为迁移搭建基架,以便为模型创建一组初始表
dotnet ef migrations add InitialCreate

# database update 命令创建数据库并向其应用新的迁移
dotnet ef database update

dotnet ef migrations add InitialCreate 创建描述表结构的代码文件

EF Core 有两个工具集

  1. .NET Core 命令行接口 (CLI) 工具可用于 Windows、Linux 或 macOS。 这些命令以 dotnet ef 开头。
  2. 包管理器控制台 (PMC) 工具在 Windows 上的 Visual Studio 中运行。 这些命令以动词开头,例如 Add-MigrationUpdate-Database

为了跨平台 应用,同时也便于编写Shell脚本,建议使用 .NET Core CLI ,不依赖于 Visual Studio

在 ASP.NET Core 中初始化数据库

这是另一种创建表结构,初始化表数据的方式,而不是用CLI,这是在启动ASP.NET Core时执行。

用这种方法,无需 Migrations代码文件,也无需 b => b.MigrationsAssembly("WebApi") ,将在程序启动时,创建表结构(context.Database.EnsureCreated();),当然创建完表结构后,可以设定数据库种子(初始化表数据)

参考:ASP.NET Core 中的 Razor Pages 和 Entity Framework Core - 第 1 个教程(共 8 个) | Microsoft Docs

创建数据库

Program.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
using ContosoUniversity.Data;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;

namespace ContosoUniversity
{
public class Program
{
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();

CreateDbIfNotExists(host);

host.Run();
}

private static void CreateDbIfNotExists(IHost host)
{
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<SchoolContext>();
context.Database.EnsureCreated();
// DbInitializer.Initialize(context);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred creating the DB.");
}
}
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}

如果有上下文的数据库,则 EnsureCreated 方法不执行任何操作。 如果没有数据库,则它将创建数据库和架构。 EnsureCreated 启用以下工作流来处理数据模型更改:

  • 删除数据库。 任何现有数据丢失。
  • 更改数据模型。 例如,添加 EmailAddress 字段。
  • 运行应用。
  • EnsureCreated 创建具有新架构的数据库。

在无需保存数据的情况下,当架构快速发展时,此工作流在早期开发过程中表现良好。 如果需要保存已输入数据库的数据,情况就有所不同了。 如果是这种情况,请使用迁移。

设定数据库种子

Data/DbInitializer.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
using ContosoUniversity.Data;
using ContosoUniversity.Models;
using System;
using System.Linq;

namespace ContosoUniversity.Data
{
public static class DbInitializer
{
public static void Initialize(SchoolContext context)
{
context.Database.EnsureCreated();

// Look for any students.
if (context.Students.Any())
{
return; // DB has been seeded
}

var students = new Student[]
{
new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2019-09-01")},
new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2017-09-01")},
new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2018-09-01")},
new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2017-09-01")},
new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2017-09-01")},
new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2016-09-01")},
new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2018-09-01")},
new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2019-09-01")}
};

context.Students.AddRange(students);
context.SaveChanges();
}
}

Q&A

Q: EF Core 创建数据库 报错: 'Method 'Create' in type 'MySql.Data.EntityFrameworkCore.Query.Internal.My......

A: 降低设计器版本到 3.x

1
2
3
4
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.7">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>

Q:

1
dotnet ef migrations add InitialCreate
1
2
3
Your target project 'WebApi' doesn't match your migrations assembly 'Repositories'. Either change your target project or change your migrations assembly.
Change your migrations assembly by using DbContextOptionsBuilder. E.g. options.UseSqlServer(connection, b => b.MigrationsAssembly("WebApi")). By default, the migrations assembly is the assembly containing the DbContext.
Change your target project to the migrations project by using the Package Manager Console's Default project drop-down list, or by executing "dotnet ef" from the directory containing the migrations project.

A: WebApi.Startup.ConfigureServices

1
2
services.AddDbContext<RemDbContext>(options =>
options.UseMySQL(connStr, b => b.MigrationsAssembly("WebApi")));

即, dotnet ef 的 默认 Migration 位于 DbContext 所在 Assembly,需要手动设置 MigrationsAssembly

WebApi 即 AssemblyName 可用下方代码获取

1
string migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

Q: 当多个 DbContext.Database.EnsureCreated() 时,只有第一个有效?

A: 是的,因为 EnsureCreated() 保证数据库被创建(存在),当第一个执行后,就会有数据库、表,

所以,当后面的 EnsureCreated() 执行时,由于已经存在数据库,所以不做任何操作

这个时候,只有对后面的调用 Migrate(),例如下方:

1
2
3
this._applicationDbContext.Database.EnsureCreated();
this._configurationDbContext.Database.Migrate();
this._persistedGrantDbContext.Database.Migrate();

当然,也可以全部采用 Migrate():

1
2
3
this._applicationDbContext.Database.Migrate();
this._configurationDbContext.Database.Migrate();
this._persistedGrantDbContext.Database.Migrate();

注意:Migrate() 必须先生成 Migrations 代码文件,可使用 .NET CLI 生成:

1
2
3
4
5
dotnet ef migrations add InitialAspNetCoreIdentityDbMigration -c ApplicationDbContext -o Migrations/AspNetCoreIdentityDb

dotnet ef migrations add InitialIdentityServerPersistedGrantDbMigration -c PersistedGrantDbContext -o Migrations/IdentityServer/PersistedGrantDb

dotnet ef migrations add InitialIdentityServerConfigurationDbMigration -c ConfigurationDbContext -o Migrations/IdentityServer/ConfigurationDb

补充

参考

感谢帮助!