我可以将依赖项注入迁移(使用 EF-Core 代码优先迁移)吗?

Can I inject dependency into migration (using EF-Core code-first migrations)?

我试图将 IConfiguration 注入迁移(在构造函数中),但出现异常:"No parameterless constructor defined for this object."

任何解决方法?

你不能,迁移需要能够 运行 在你的应用程序上下文之外。

由于 Entity-framework 命令行工具会分析您的代码但不会 运行 startup.cs class.

也是不可取的。您的迁移应该简单明了,不依赖于任何东西。如果是这样,它可能会导致主要的运行时间副作用,其中缺少配置可能会导致生产中缺少表或列。

补充建议

如果它涉及很多 small/equal/manual 变化。最好的方法是生成迁移文件。为什么?这样您的迁移将是确定性的:您知道结果会是什么。如果迁移中的一行失败,那么很容易(呃)修复它的原因很简单明了。

有一种方法可以做您想做的事。在我的场景中,我想通过 DbContext 在连接字符串中使用数据库名称。使用 EF 核心 2.1.1。 The code is modified from here

创建自定义 MigrationsAssembly 服务

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Migrations.Internal;
using System;
using System.Reflection;

public class ContextAwareMigrationsAssembly : MigrationsAssembly
{
    private readonly DbContext context;

    public ContextAwareMigrationsAssembly(
        ICurrentDbContext currentContext,
        IDbContextOptions options,
        IMigrationsIdGenerator idGenerator,
        IDiagnosticsLogger<DbLoggerCategory.Migrations> logger) : base(currentContext, options, idGenerator, logger)
    {
        context = currentContext.Context;
    }

    /// <summary>
    /// Modified from http://weblogs.thinktecture.com/pawel/2018/06/entity-framework-core-changing-db-migration-schema-at-runtime.html
    /// </summary>
    /// <param name="migrationClass"></param>
    /// <param name="activeProvider"></param>
    /// <returns></returns>
    public override Migration CreateMigration(TypeInfo migrationClass, string activeProvider)
    {
        var hasCtorWithDbContext = migrationClass
                .GetConstructor(new[] { typeof(DbContext) }) != null;

        if (hasCtorWithDbContext)
        {
              var instance = (Migration)Activator.CreateInstance(migrationClass.AsType(), context);
              instance.ActiveProvider = activeProvider;
              return instance;
        }

        return base.CreateMigration(migrationClass, activeProvider);
    }
}

用您自定义的 class

替换 DbContext 中的 IMigrationAssembly 服务
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.ReplaceService<IMigrationsAssembly, ContextAwareMigrationsAssembly>();
}

然后您可以在迁移中添加一个 DbContext 参数。

public Migration20180801(DbContext context)
{
    DatabaseName = context.Database.GetDbConnection().Database;
}

在您的情况下,您可以将所有 DbContext 引用替换为 IConfiguration 以及 CreateMigration 覆盖中的相关实例。

如果只是关于您的 connection-string(是吗?),您可能需要检查 ,这基本上表明您的 startup-project(而不是您的 migrations-project):

var myConnectionString = Configuration.GetConnectionString(myConnectionStringName);
services.AddDbContext<MyDbContext>(options => options.UseSqlServer(
    myConnectionString ,
    x => x.MigrationsAssembly(myDbContextAssemblyName)));