• Entity Framework Core


    管理数据库架构

      EF Core提供了两种保持EF Core模型和数据库模式同步的主要方法。要在两者之间进行选择,请确定您的EF核心模型还是数据库模式是真实的来源。

       1、如果您希望您的EF核心模型是真实的来源,那么使用迁移。当您对EF核心模型进行更改时,这种方法将递增地对数据库应用相应的模式更改,以便它与EF核心模型保持兼容。

       2、如果您想让数据库模式成为事实的来源,请使用反向工程这种方法允许您通过反向工程数据库模式到EF核心模型来构建DbContext和实体类型类。

      

      create and drop APIs 还可以从您的EF核心模型创建数据库模式。但是,它们主要用于测试、原型和其他可以删除数据库的场景。

    一、迁移

      在现实世界的项目中,数据模型随着功能的实现而变化:添加和删除新的实体或属性,并且需要相应地更改数据库模式以保持与应用程序同步。EF Core中的迁移特性提供了一种增量更新数据库模式的方法,使其与应用程序的数据模型保持同步,同时在数据库中保留现有数据。

         迁移的功能如下:

      •   当引入数据模型更改时,开发人员使用 EF Core 工具添加相应的迁移,以描述使数据库架构保持同步所需的更新。EF Core 将当前模型与旧模型的快照进行比较,以确定差异,并生成迁移源文件;文件可在项目的源代码管理中进行跟踪,如任何其他源文件。
      •   生成新的迁移后,可通过多种方式将其应用于数据库。 EF Core 在一个特殊的历史记录表中记录所有应用的迁移,使其知道哪些迁移已应用,哪些迁移尚未应用。

      

      首先,必须安装 EF Core 命令行工具

      1、管理迁移

        当模型发生更改时,将在正常开发过程中添加和删除迁移,并将迁移文件签入项目的源代码管理。 如果 DbContext 与启动项目位于不同程序集中,可以在包管理器控制台工具或 .NET Core CLI 工具中显式指定目标和启动项目。

        1、添加迁移

          更改模型后,可以为该更改添加迁移:

    Add-Migration AddBlogCreatedTimestamp

          迁移名称可以像版本控制系统中的提交消息一样使用。例如,如果更改是您的Blog实体上的一个新的CreatedTimestamp属性,您可能会选择一个类似AddBlogCreatedTimestamp的名称。

           Migrations目录下的三个文件被添加到您的项目中:

        • XXXXXXXXXXXXXX_AddCreatedTimestamp.cs--主迁移文件。包含应用迁移(Up)和恢复迁移(Down)所需的操作。
        • XXXXXXXXXXXXXX_AddCreatedTimestamp.Designer.cs--迁移元数据文件。包含EF使用的信息。
        • MyContextModelSnapshot.cs--当前模型的快照。用于确定添加下一个迁移时发生的更改。

          文件名中的时间戳有助于保持它们按时间顺序排列,因此您可以看到更改的进展。

          名称空间

          您可以随意移动迁移文件并手动更改它们的名称空间。新迁移作为上一次迁移的兄弟迁移创建。或者,您可以在生成时指定目录,如下所示:

    Add-Migration InitialCreate -OutputDir YourDirectory

          在EF Core 5.0中,您还可以使用-Namespace更改独立于目录的名称空间。

        2、自定义迁移代码

          尽管 EF Core 通常会创建准确的迁移,但应始终查看代码,并确保其对应于所需的更改;在某些情况下,它甚至是必需的。

          重命名列   --尤其要注意这点

          定制迁移时,一个值得注意的例子是重命名属性时。例如,如果你将一个属性从Name重命名为FullName, EF Core将生成以下迁移:

    migrationBuilder.DropColumn(
        name: "Name",
        table: "Customers");
    
    migrationBuilder.AddColumn<string>(
        name: "FullName",
        table: "Customers",
        nullable: true);

          EF Core 通常无法知道何时要删除某一列,并创建一个新的 (两个不同的更改) ,以及应重命名列。 如果以上迁移按原样应用,则所有客户名称都将丢失。 若要重命名列,请将上面生成的迁移替换为以下内容:

    migrationBuilder.RenameColumn(
        name: "Name",
        table: "Customers",
        newName: "FullName");

          当某个操作可能会导致数据丢失(例如删除某列),搭建迁移基架过程将对此发出警告。 如果看到此警告,务必检查迁移代码的准确性。

          添加原始SQL

          重命名列时,可以通过内置 API 来实现,在许多情况下,这是不可能的。 例如,我们可能希望将现有的 FirstName 和属性替换为 LastName 一个新的 FullName 属性。 EF Core 生成的迁移如下:

    migrationBuilder.DropColumn(
        name: "FirstName",
        table: "Customer");
    
    migrationBuilder.DropColumn(
        name: "LastName",
        table: "Customer");
    
    migrationBuilder.AddColumn<string>(
        name: "FullName",
        table: "Customer",
        nullable: true);

          如前所述,这会导致不需要的数据丢失。 为了传输旧列中的数据,我们会重新排列迁移并引入原始 SQL 操作,如下所示:

    migrationBuilder.AddColumn<string>(
        name: "FullName",
        table: "Customer",
        nullable: true);
    
    migrationBuilder.Sql(
    @"
        UPDATE Customer
        SET FullName = FirstName + ' ' + LastName;
    ");
    
    migrationBuilder.DropColumn(
        name: "FirstName",
        table: "Customer");
    
    migrationBuilder.DropColumn(
        name: "LastName",
        table: "Customer");

          通过原始 SQL 进行任意更改

          原始SQL还可以用来管理EF Core不知道的数据库对象。为了做到这一点,添加一个迁移而不做任何模型更改;将生成一个空迁移,然后您可以使用原始SQL操作填充该迁移。例如,下面的迁移创建了一个SQL Server存储过程:

    migrationBuilder.Sql(
    @"
        EXEC ('CREATE PROCEDURE getFullName
            @LastName nvarchar(50),
            @FirstName nvarchar(50)
        AS
            RETURN @LastName + @FirstName;')");

          当语句必须是SQL批处理中的第一个或唯一一个语句时,使用EXEC。它还可以用于解决幂等迁移脚本中的解析器错误,当前表中不存在引用的列时,这种错误可能发生。

          这可用于管理数据库的任何方面,包括:

        • 全文搜索
        • 函数
        • 触发器
        • 视图
        • 存储过程

          

          在大多数情况下,当应用迁移时,EF Core会自动将每个迁移包装到它自己的事务中。不幸的是,某些数据库中的某些迁移操作不能在事务内执行;对于这些情况,您可以通过将suppressTransaction: true传递给migrationBuilder.Sql来退出事务。

          如果DbContext与启动项目位于不同的程序集中,您可以在Package Manager控制台工具或. net Core CLI工具中显式地指定目标和启动项目。  

        3、删除迁移

          有时,你可能在添加迁移后意识到需要在应用迁移前对 EF Core 模型作出其他更改。 要删除上个迁移,请使用如下命令:

    Remove-Migration

          删除迁移后,可对模型作出其他更改,然后再次添加迁移。

          注意不要删除已经应用到生产数据库的任何迁移。如果不这样做,您将无法恢复它,并且可能会破坏后续迁移所做的假设。

        3、列出迁移

          列出所有已存在的迁移:

    Get-Migration

          这是EF Core 5的新特性。

        5、重置所有迁移

          在某些极端情况下,可能需要删除所有迁移并重新开始。这可以通过删除Migrations文件夹和删除数据库轻松完成(会删除数据);此时,您可以创建一个新的初始迁移,它将包含您整个当前模式。

           还可以重置所有迁移并创建一个迁移,而不会丢失数据。这有时被称为“squashing”(挤压?),涉及一些手工工作:

        • 删除 迁移 文件夹
        • 创建新迁移并为其生成 SQL 脚本(如何生成见后文)
        • 在数据库中,删除迁移历史记录表中的所有行
        • 将单个行插入到迁移历史记录中,记录已应用的第一个迁移,因为表已经存在。 Insert SQL 是上面生成的 SQL 脚本中的最后一个操作。

          删除 迁移 文件夹时,任何 自定义迁移代码都将丢失。 若要保留任何自定义,必须手动将其应用到新的初始迁移。

      2、应用迁移

        添加迁移后,需要对其进行部署并将其应用于数据库。 有多种策略可用于执行此操作,某些策略更适用于生产环境,而另一些则用于开发生命周期。无论部署策略如何,都应始终检查生成的迁移并在应用到生产数据库之前对其进行测试。 如果尝试对列进行重命名,则迁移可能会删除列,如果应用到数据库,则可能会因各种原因而失败。

        1、SQL脚本

        部署到生产数据库的建议方法是生成 SQL 脚本。 此策略的优点包括:

      • 可以查看 SQL 脚本的准确性;这一点很重要,因为对生产数据库应用架构更改可能会导致数据丢失。
      • 在某些情况下,可以根据生产数据库的特定需求调整这些脚本。
      • SQL 脚本可以与部署技术结合使用,甚至可以作为 CI 过程的一部分生成。
      • SQL 脚本可提供给 DBA,可以单独管理和存档。

        基本用法

        下面的内容生成一个从空白数据库到最新迁移的 SQL 脚本:

    Script-Migration

        使用From

        以下生成从给定的迁移到最新迁移的 SQL 脚本:

    Script-Migration AddNewTables

        使用From和To

        下面生成一个SQL脚本,从指定的 from 迁移到指定的To迁移(您可以使用比to更新的from来生成回滚脚本。请注意潜在的数据丢失情况):

    Script-Migration AddNewTables AddAuditTable

        脚本生成接受以下两个自变量,以指示应生成的迁移范围:

      • from 迁移应是运行该脚本前应用到数据库的最后一个迁移。 如果未应用任何迁移,请指定 0(默认值)。
      • to 迁移是运行该脚本后应用到数据库的最后一个迁移。 它默认为项目中的最后一个迁移。

        2、幂等SQL脚本

         上面生成的 SQL 脚本只能应用于将架构从一个迁移更改到另一个迁移;你需要负责适当地应用脚本,并且仅适用于处于正确迁移状态的数据库。 EF Core 还支持生成 幂等 脚本,这些脚本可以在内部检查哪些迁移已经被应用(通过迁移历史表),并且只应用缺失的迁移。 如果您不知道最后一次应用到数据库的迁移,或者要部署到多个数据库(每个数据库都在不同的迁移上),这会很有用。

    以下生成幂等迁移:

    Script-Migration -Idempotent

        3、命令行工具

          可以使用EF命令行工具对数据库进行迁移。虽然这种方法对于本地开发和迁移测试很有效,但对于管理生产数据库并不理想:

        • 该工具直接应用SQL命令,而不给开发人员检查或修改它们的机会。在生产环境中,这可能很危险。
        • 必须在生产服务器上安装。net SDK和EF工具。

          以下操作将您的数据库更新到最新的迁移:

    Update-Database

          下面的代码更新你的数据库到一个给定的迁移:

    Update-Database AddNewTables

          请注意,这种方式也可以用于回滚到以前的迁移(常记:注意潜在的数据丢失情况)。

        4、运行时迁移

          应用程序本身可以通过编程方式应用迁移,通常在启动期间。虽然这种方法对于本地开发和迁移测试是有效的,但它不适用于管理生产数据库,原因如下:

        • 如果你的应用程序的多个实例正在运行,这两个应用程序都可以尝试同时应用迁移和失败 (或更糟,导致数据损坏) 。
        • 同样,如果应用程序在另一个应用程序迁移它时访问数据库,这可能会导致严重问题。
        • 应用程序必须具有提升的访问权限才能修改数据库架构。 在生产环境中限制应用程序的数据库权限通常是一种很好的做法
        • 在出现问题时,必须能够回滚应用的迁移。 其他策略可轻松地提供这种情况。
        • SQL 命令直接应用于程序,没有为开发人员提供检查或修改的机会。 这在生产环境中可能会很危险。

          要以编程方式应用迁移,可以调用context.Database.Migrate()。例如,一个典型的ASP.NET应用程序可以做到以下几点:

    public static void Main(string[] args)
    {
        var host = CreateHostBuilder(args).Build();
    
        using (var scope = host.Services.CreateScope())
        {
            var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
            db.Database.Migrate();
        }
    
        host.Run();
    }

          注意,Migrate()构建在IMigrator服务之上,可以用于更高级的场景。使用myDbContext.GetInfrastructure(). getservice <IMigrator>()来访问它。

        • 在生产中使用此方法之前请仔细考虑。经验表明,这种部署策略的简单性被它所产生的问题压倒了。请考虑从迁移生成SQL脚本。
        • 请勿在 Migrate() 前调用 EnsureCreated()。 EnsureCreated() 会绕过迁移创建架构,这会导致 Migrate() 失败。

      3、团队环境

        在团队环境中使用迁移时,请特别注意模型快照文件。 此文件可以告诉你队友的迁移是否与你的迁移完全合并,或者是否需要在共享之前重新创建您的迁移来解决冲突。

        1、合并

          合并团队成员的迁移时,可能会在模型快照文件中出现冲突。 如果这两个更改不相关,则合并很简单,两个迁移可以共存。 例如,你可能会在客户实体类型配置中出现合并冲突,如下所示:

    <<<<<<< Mine
    b.Property<bool>("Deactivated");
    =======
    b.Property<int>("LoyaltyPoints");
    >>>>>>> Theirs

          由于这两个属性都需要存在于最终模型中,因此请通过添加这两个属性来完成合并。 在许多情况下,版本控制系统可能会自动合并此类更改:

    b.Property<bool>("Deactivated");
    b.Property<int>("LoyaltyPoints");

          在这些情况下,迁移和队友的迁移彼此独立。 由于可以首先应用其中的任何一个,因此在与团队共享之前,无需对迁移进行任何其他更改。

        2、解决冲突

          有时,在合并模型快照模型时,您会遇到真正的冲突。例如,您和您的队友可能已经分别重命名了相同的属性:

    <<<<<<< Mine
    b.Property<string>("Username");
    =======
    b.Property<string>("Alias");
    >>>>>>> Theirs

          如果遇到这种冲突,请通过重新创建迁移解决此问题。 请执行下列步骤:

      1. 在合并前中止合并并回退到工作目录
      2. 删除迁移 (但保留模型更改)
      3. 将队友的更改合并到工作目录
      4. 重新添加迁移

          执行此操作后,可以按正确的顺序应用两个迁移。 首先应用队友的迁移,将列重命名为 Alias,此后,迁移会将其重命名为 Username

      4、自定义操作

        MigrationBuilder API允许您在迁移过程中执行许多不同类型的操作,但它还远远不够详尽。然而,API也是可扩展的,允许您定义自己的操作。有两种方法可以扩展API:使用Sql()方法,或者通过定义自定义的MigrationOperation对象。

        为了说明这一点,让我们来看看如何实现使用每种方法创建数据库用户的操作。在我们的迁移中,我们希望能够编写以下代码:

    migrationBuilder.CreateUser("SQLUser1", "Password");

        1、使用MigrationBuilder.Sql()

          实现自定义操作的最简单方法是定义调用的扩展方法 MigrationBuilder.Sql() 。 下面是生成相应 Transact-sql 的示例:

    static OperationBuilder<SqlOperation> CreateUser(
        this MigrationBuilder migrationBuilder,
        string name,
        string password)
        => migrationBuilder.Sql($"CREATE USER {name} WITH PASSWORD '{password}';");

        当语句必须是SQL批处理中的第一个或唯一一个语句时,请使用EXEC函数。它还可能需要解决幂等迁移脚本中的解析器错误,当表中当前不存在引用的列时,这种错误可能发生。

        如果你的迁移需要支持多个数据库提供程序,则可以使用 MigrationBuilder.ActiveProvider 属性。 下面是同时支持 Microsoft SQL Server 和 PostgreSQL 的示例:

    static OperationBuilder<SqlOperation> CreateUser(
        this MigrationBuilder migrationBuilder,
        string name,
        string password)
    {
        switch (migrationBuilder.ActiveProvider)
        {
            case "Npgsql.EntityFrameworkCore.PostgreSQL":
                return migrationBuilder
                    .Sql($"CREATE USER {name} WITH PASSWORD '{password}';");
    
            case "Microsoft.EntityFrameworkCore.SqlServer":
                return migrationBuilder
                    .Sql($"CREATE USER {name} WITH PASSWORD = '{password}';");
        }
    
        throw new Exception("Unexpected provider.");
    }

          此方法仅在知道将应用自定义操作的每个提供程序时才有效。

        2、使用自定义的MigrationOperation对象。

          要将自定义操作与SQL解耦,可以定义自己的MigrationOperation来表示它。然后将操作传递给提供程序,以便它生成的适当SQL:

    class CreateUserOperation : MigrationOperation
    {
        public string Name { get; set; }
        public string Password { get; set; }
    }

          使用这种方法,扩展方法只需要将其中一个操作添加到MigrationBuilder.Operations:

    static OperationBuilder<CreateUserOperation> CreateUser(
        this MigrationBuilder migrationBuilder,
        string name,
        string password)
    {
        var operation = new CreateUserOperation
        {
            Name = name,
            Password = password
        };
        migrationBuilder.Operations.Add(operation);
    
        return new OperationBuilder<CreateUserOperation>(operation);
    }

          这种方法要求每个提供程序都知道如何在其IMigrationsSqlGenerator服务中为该操作生成SQL。下面是一个覆盖SQL Server生成器以处理新操作的示例:

    class MyMigrationsSqlGenerator : SqlServerMigrationsSqlGenerator
    {
        public MyMigrationsSqlGenerator(
            MigrationsSqlGeneratorDependencies dependencies,
            IMigrationsAnnotationProvider migrationsAnnotations)
            : base(dependencies, migrationsAnnotations)
        {
        }
    
        protected override void Generate(
            MigrationOperation operation,
            IModel model,
            MigrationCommandListBuilder builder)
        {
            if (operation is CreateUserOperation createUserOperation)
            {
                Generate(createUserOperation, builder);
            }
            else
            {
                base.Generate(operation, model, builder);
            }
        }
    
        private void Generate(
            CreateUserOperation operation,
            MigrationCommandListBuilder builder)
        {
            var sqlHelper = Dependencies.SqlGenerationHelper;
            var stringMapping = Dependencies.TypeMappingSource.FindMapping(typeof(string));
    
            builder
                .Append("CREATE USER ")
                .Append(sqlHelper.DelimitIdentifier(operation.Name))
                .Append(" WITH PASSWORD = ")
                .Append(stringMapping.GenerateSqlLiteral(operation.Password))
                .AppendLine(sqlHelper.StatementTerminator)
                .EndCommand();
        }
    }

          将默认迁移 sql 生成器服务替换为已更新的:

    protected override void OnConfiguring(DbContextOptionsBuilder options)
        => options
            .UseSqlServer(_connectionString)
            .ReplaceService<IMigrationsSqlGenerator, MyMigrationsSqlGenerator>();

      5、使用独立的项目

        您可能希望将迁移存储在一个与包含DbContext的项目不同的项目中。您还可以使用此策略来维护多组迁移,例如,一组用于开发,另一组用于发布到发布的升级。

        步骤:

      1. 创建一个新的类库。
      2. 添加对 DbContext 项目的引用。
      3. 将迁移和模型快照文件移动到类库。如果您没有现有的迁移,那么在包含DbContext的项目中生成一个迁移,然后移动它。这很重要,因为如果migrations项目不包含现有的迁移,那么Add-Migration命令将无法找到DbContext。
      4. 配置迁移程序集:
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection"),
                x => x.MigrationsAssembly("WebApplication1.Migrations")));
      5. 从 启动 项目添加对迁移项目的引用。
        <ItemGroup>
          <ProjectReference Include="..WebApplication1.MigrationsWebApplication1.Migrations.csproj">
        </ItemGroup>

        如果这导致循环依赖,您可以改为更新migrations项目的基本输出路径:

        <PropertyGroup>
          <BaseOutputPath>..WebApplication1in</BaseOutputPath>
        </PropertyGroup>

        如果一切正常,应能够向项目添加新的迁移:

    Add-Migration NewMigration -Project WebApplication1.Migrations

      6、多个提供程序

        EF Core工具只支持活动提供程序(active provider)的迁移。然而,有时您可能希望在DbContext中使用多个提供者(例如Microsoft SQL Server和SQLite)。通过维护多个迁移集(每个提供者一个集合、组)来处理这个问题,并为每个集合添加一个迁移。

        1、使用多种DbContext上下文类型

         创建多个迁移集的一种方法是为每个提供程序使用一个 DbContext 类型:

    class SqliteBlogContext : BlogContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder options)
            => options.UseSqlite("Data Source=my.db");
    }

           添加新迁移时指定上下文类型:

    Add-Migration InitialCreate -Context BlogContext -OutputDir MigrationsSqlServerMigrations
    Add-Migration InitialCreate -Context SqliteBlogContext -OutputDir MigrationsSqliteMigrations

           无需指定输出目录即可进行后续迁移,因为它们是以同级方式创建的。

        2、使用一个上下文类型

            也可以使用一个DbContext类型。这目前需要将迁移转移到单独的程序集中。

          从EF Core 5.0开始,你可以通过工具将参数传递到应用程序中。这可以使工作流程更加流畅,从而避免在运行工具时不得不对项目进行手动更改。

          在使用通用主机时,有一种模式可以很好地工作:

    public static IHostBuilder CreateHostBuilder(string[] args)
        => Host.CreateDefaultBuilder(args)
            .ConfigureServices(
                (hostContext, services) =>
                {
                    services.AddHostedService<Worker>();
    
                    // Set the active provider via configuration
                    var configuration = hostContext.Configuration;
                    var provider = configuration.GetValue("Provider", "SqlServer");
    
                    services.AddDbContext<BlogContext>(
                        options => _ = provider switch
                        {
                            "Sqlite" => options.UseSqlite(
                                configuration.GetConnectionString("SqliteConnection"),
                                x => x.MigrationsAssembly("SqliteMigrations")),
    
                            "SqlServer" => options.UseSqlServer(
                                configuration.GetConnectionString("SqlServerConnection"),
                                x => x.MigrationsAssembly("SqlServerMigrations")),
    
                            _ => throw new Exception($"Unsupported provider: {provider}")
                        });
                });

          由于默认主机生成器从命令行参数读取配置,因此您可以在运行工具时指定提供程序:

    Add-Migration MyMigration -Args "--provider SqlServer"
    Add-Migration MyMigration -Args "--provider Sqlite"

      7、自定义历史记录表

        默认情况下,EF Core通过在一个名为__EFMigrationsHistory的表中记录它们来跟踪哪些迁移已经被应用到数据库。出于各种原因,您可能希望定制此表以更好地满足您的需求。(如果在应用迁移  自定义迁移历史记录表,则需要负责更新数据库中的现有表。)

        1、自定义架构和表名称

          你可以使用OnConfiguring()中的MigrationsHistoryTable()方法来更改模式和表名(或ASP.NET Core上的ConfigureServices())下面是一个使用SQL Server EF核心提供程序的示例:

    protected override void OnConfiguring(DbContextOptionsBuilder options)
        => options.UseSqlServer(
            _connectionString,
            x => x.MigrationsHistoryTable("__MyMigrationsHistory", "mySchema"));

        2、其他更改

          若要配置表的其他方面,请覆盖并替换特定于提供程序的IHistoryRepository服务。下面是一个将SQL Server上的MigrationId列名称更改为Id的示例:

    protected override void OnConfiguring(DbContextOptionsBuilder options)
        => options
            .UseSqlServer(_connectionString)
            .ReplaceService<IHistoryRepository, MyHistoryRepository>();
    class MyHistoryRepository : SqlServerHistoryRepository
    {
        public MyHistoryRepository(HistoryRepositoryDependencies dependencies)
            : base(dependencies)
        {
        }
    
        protected override void ConfigureTable(EntityTypeBuilder<HistoryRow> history)
        {
            base.ConfigureTable(history);
    
            history.Property(h => h.MigrationId).HasColumnName("Id");
        }
    }

          SqlServerHistoryRepository 位于内部命名空间内部

    二、反向工程

      逆向工程是基于数据库模式搭建实体类型类和DbContext类的过程。可以使用EF核心包管理器控制台(PMC)工具的scaffold - dbcontext命令或. net命令行接口(CLI)工具的dotnet EF dbcontext scaffold命令来执行。

      1、安装

        在逆向工程之前,您需要安装PMC工具(仅Visual Studio)或CLI工具。

          您还需要为想要反向工程的数据库模式安装适当的数据库提供程序。

      2、连接字符串

        该命令的第一个参数是到数据库的连接字符串。工具将使用这个连接字符串来读取数据库模式。

           如何引用和转义连接字符串取决于您正在使用哪个shell来执行命令。有关详细信息,请参考您的shell文档。例如,PowerShell要求转义$字符,但不要求转义。

    Scaffold-DbContext 'Data Source=(localdb)MSSQLLocalDB;Initial Catalog=Chinook' Microsoft.EntityFrameworkCore.SqlServer

       配置和用户密码

          在ASP.NET Core项目中,你可以使用Name=<connection-string>语法从配置中读取连接字符串。

          这可以很好地与Secret Manager工具一起工作,使数据库密码与代码库分离。

          .Net Core CLI:

    dotnet user-secrets set ConnectionStrings.Chinook "Data Source=(localdb)MSSQLLocalDB;Initial Catalog=Chinook"
    dotnet ef dbcontext scaffold Name=ConnectionStrings.Chinook Microsoft.EntityFrameworkCore.SqlServer

      3、提供程序名称

        第二个参数是提供程序名称。 提供程序名称通常与提供程序的 NuGet 包名称相同。

      4、指定表

        默认情况下,将数据库架构中的所有表反向工程为实体类型。 您可以通过指定架构和表来限制对哪些表进行反向工程:

        -Schemas选项可用于包含架构中的每个表,而-Tables可用于包含特定的表。

        要包含多个表,请使用数组:

    Scaffold-DbContext ... -Tables Artist, Album

      5、保留名称

        默认情况下,表名和列名是固定的,以便更好地匹配.net类型和属性的命名约定。在PMC中指定-UseDatabaseNames开关或在.net Core CLI中指定——use-database-names选项将禁用此行为,尽可能保留原始的数据库名称。无效的.net标识符仍然会被修复,像导航属性这样的合成名称仍然会遵循.net命名约定。

      6、使用Fluent API还是数据批注的方式

        默认情况下,实体类型是使用熟知 API 配置的。 指定 -DataAnnotations (PMC) 或 --data-annotations ( .NET Core CLI) 改为使用数据批注(如果可能)。

      7、DbContext 名称

        默认情况下,基架 DbContext 类名称将为带有后缀 Context 的数据库的名称。 若要指定其他项,请在 PMC 中使用-Context参数, 在 .NET Core CLI 中使用--context 参数。

      8、目录和命名空间

        实体类和DbContext类被搭建到项目的根目录中,并使用项目的默认名称空间。

        你可以使用-OutputDir指定搭建类的目录,-ContextDir可以用来搭建DbContext类到实体类型类的单独目录中:

    Scaffold-DbContext ... -ContextDir Data -OutputDir Models

        默认情况下,名称空间将是根名称空间加上项目根目录下任何子目录的名称。但是,从EFCore 5.0开始,您可以使用-Namespace覆盖所有输出类的名称空间。还可以使用-ContextNamespace覆盖DbContext类的名称空间:

    Scaffold-DbContext ... -Namespace Your.Namespace -ContextNamespace Your.DbContext.Namespace

      9、工作原理

        逆向工程从读取数据库模式开始。它读取关于表、列、约束和索引的信息。

        接下来,它使用schema信息来创建EF核心模型。表用于创建实体类型;列用于创建属性;外键用于创建关系。

        最后,使用该模型生成代码。它构建了相应的实体类型类、Fluent API和数据注释,用以从应用程序中重新创建相同的模型。

      10、限制

      • 不是有关模型的所有内容都可以使用数据库架构来表示。 例如,有关 继承层次结构、 附属类型和 表拆分 的信息在数据库架构中不存在。 因此,这些构造永远不会经过反向工程。
      • 此外,EF Core 提供程序可能不支持 某些列类型 。 这些列不会包含在模型中。
      • 可以在 EF Core 模型中定义 并发标记,以防止两个用户同时更新同一实体。 某些数据库具有特殊类型来表示此类型的列 (例如,SQL Server 中的 rowversion) ,在这种情况下,我们可以对此信息进行反向工程;但是,其他并发令牌不会进行反向工程。
      • 反向工程当前不支持c # 8 可为 Null 的引用类型功能: EF Core 始终会生成假定禁用该功能的 c # 代码。 例如,可以为空的文本列将搭建为一个类型为string的属性,而不是【string?】配置属性是否是必须的使用Fluent API 或数据批注(原文:For example, nullable text columns will be scaffolded as a property with type string , not string?, with either the Fluent API or Data Annotations used to configure whether a property is required or not. )。 您可以编辑搭建好的代码,并用c#的可空注释替换它们

      7、自定义模型

          由EF Core生成的代码就是你的代码。您可以随意更改它。只有当您再次对相同的模型进行逆向工程时,它才会重新生成。搭建的代码表示一个可用于访问数据库的模型,但它肯定不是惟一可用的模型。

         可以根据需要,自定义实体类型类和DbContext类。例如,您可以选择重命名类型和属性、引入继承层次结构或将表拆分为多个实体。您还可以从模型中删除非惟一索引、未使用的序列和导航属性、可选标量属性和约束名称。

         您还可以在单独的文件中使用另一个分部类(partial class)添加额外的构造函数、方法、属性等。即使您打算再次对模型进行反向工程,这种方法也仍然有效。

      8、更新模型

        在对数据库进行更改之后,您可能需要更新EF核心模型来反映这些更改。如果数据库更改很简单,那么最简单的方法就是手动对EF核心模型进行更改。例如,重命名表或列、删除列或更新列的类型都是在代码中要做的微小更改。

        然而,手动进行更重要的更改并不容易。一个常见的工作流是使用-Force (PMC)或——force (CLI)从数据库再次逆向工程模型,用更新的模型覆盖现有的模型。

        如果您从数据库中再次对模型进行反向工程,则对这些文件所做的任何更改都将丢失。

  • 相关阅读:
    原型模式
    简单工厂模式与工厂方法模式
    监听器 Listener
    代理模式
    装饰模式
    软件设计的原则
    事务的特性和隔离级别
    JDBC事务(三)ThreadLocal绑定Connection
    JDBC事务(二)转账示例
    JDBC事务(一)
  • 原文地址:https://www.cnblogs.com/hiwuchong/p/14160438.html
Copyright © 2020-2023  润新知