Entity Framework Core 总结

2022-04-01 16:23:44 浏览数 (1)

.NET Core CLI

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

代码语言:javascript复制
# 全局安装 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

代码语言:javascript复制
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

代码语言:javascript复制
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

代码语言:javascript复制
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.7">
    <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    <PrivateAssets>all</PrivateAssets>
</PackageReference>

Q:

代码语言:javascript复制
dotnet ef migrations add InitialCreate
代码语言:javascript复制
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

代码语言:javascript复制
services.AddDbContext<RemDbContext>(options =>
	options.UseMySQL(connStr, b => b.MigrationsAssembly("WebApi")));

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

WebApi 即 AssemblyName 可用下方代码获取

代码语言:javascript复制
string migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

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

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

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

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

代码语言:javascript复制
this._applicationDbContext.Database.EnsureCreated();
this._configurationDbContext.Database.Migrate();
this._persistedGrantDbContext.Database.Migrate();

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

代码语言:javascript复制
this._applicationDbContext.Database.Migrate();
this._configurationDbContext.Database.Migrate();
this._persistedGrantDbContext.Database.Migrate();

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

代码语言:javascript复制
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

参考

感谢帮助!

  • 入门 - EF Core | Microsoft Docs

本文作者: yiyun

本文链接: https://moeci.com/posts/分类-dotnet/dotnet-efcore/

版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

0 人点赞