冲扬心法

笑声激发自强,发愤、图强、飞身向上

   :: 首页  ::  ::  ::  :: 管理

管理数据库架构

  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 Your\Directory

      在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.Migrations\WebApplication1.Migrations.csproj">
      </ItemGroup>

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

      <PropertyGroup>
        <BaseOutputPath>..\WebApplication1\bin\</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 Migrations\SqlServerMigrations
Add-Migration InitialCreate -Context SqliteBlogContext -OutputDir Migrations\SqliteMigrations

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

    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)从数据库再次逆向工程模型,用更新的模型覆盖现有的模型。

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

 

posted on 2020-12-22 23:17  风雨一肩挑  阅读(484)  评论(0编辑  收藏  举报