无法创建 Entity Framework 代码优先迁移

Can't create Entity Framework code-first migrations

过去几周我一直在开发 .NET Core 6 控制台应用程序(不是 ASP.NET),现在我已经尝试实施 Entity Framework 6 次迁移。

然而,即使我重用了使用迁移的工作数据库模型中的一些代码,现在我也无法让它工作,而且由于缺少 [=16= 的输出,我也一直在努力].

由于我不记得的原因,我重用了代码的数据库项目使用了 Design-Time DbContext creation。我不知道这是否是我进行迁移的最佳方式,但至少它设法在以前的项目中工作。我以与之前相同的方式实现了所需的 IDesignTimeDbContextFactory<DbContext> 接口:

public class MySqlContextFactory : IDesignTimeDbContextFactory<MySqlContext>
{
    public MySqlContext CreateDbContext(string[] args)
    {
        DbContextOptionsBuilder optionsBuilder = new();
        ServerVersion mariaDbVersion = new MariaDbServerVersion(new Version(10, 6, 5));
        optionsBuilder.UseMySql(DatabaseCredentials.GetConnectionString(), mariaDbVersion);

        return new MySqlContext();
    }
}

public class MySqlContext : DbContext
{
    public DbSet<Endpoint> EndpointsSet { get; set; }
    
    private readonly string _connectionString;

    public MySqlContext() : base()
        => _connectionString = DatabaseCredentials.GetConnectionString();

    public MySqlContext(string connectionString) : base()
        => _connectionString = connectionString;

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => Configurator.Configure(optionsBuilder, _connectionString);

    protected override void OnModelCreating(ModelBuilder modelBuilder)
        => Configurator.Create(modelBuilder);
}

public static void Configure(DbContextOptionsBuilder optionsBuilder, string connectionString)
{
        ServerVersion mariaDbVersion = new MariaDbServerVersion(new Version(10, 6, 5));
        optionsBuilder.UseMySql(connectionString, mariaDbVersion);
}

public static void Create(ModelBuilder modelBuilder)
{
        IEnumerable<Type> types = ReflectionUtils.GetImplementedTypes(typeof(IEntityTypeConfiguration<>));
        if (types.Any())
        {
            foreach (Type entityConfigurationType in types)
            {
                modelBuilder.ApplyConfigurationsFromAssembly(entityConfigurationType.Assembly);
            }
        }
        else
        {
            Environment.Exit((int) EExitCodes.EF_MODEL_NOT_FOUND);
        }
}

但是,当我尝试创建第一个迁移时,系统提示我从 dotnet-ef 工具输出这个绝对非描述性的输出:

PS> dotnet ef migrations add Init
Build started...
Build succeeded.
PS>

但是我的项目没有进行任何迁移,也没有任何更改。因此,我决定通过在 PS 命令上附加 --verbose 标志来强制 dotnet ef 告诉我更多信息:

[...]
Build succeeded.
dotnet exec --depsfile F:\pablo\Documents\source\MyBot\bin\Debug\net6.0\MyBot.deps.json --additionalprobingpath C:\Users\pablo\.nuget\packages --runtimeconfig F:\pablo\Documents\source\MyBot\bin\Debug\net6.0\MyBot.runtimeconfig.json C:\Users\pablo\.dotnet\tools\.store\dotnet-ef.0.1\dotnet-ef.0.1\tools\netcoreapp3.1\any\tools\netcoreapp2.0\any\ef.dll migrations add Init -o Migrations\Init --assembly F:\pablo\Documents\source\MyBot\bin\Debug\net6.0\MyBot.dll --project F:\pablo\Documents\source\MyBot\MyBot.csproj --startup-assembly F:\pablo\Documents\source\MyBot\bin\Debug\net6.0\MyBot.dll --startup-project F:\pablo\Documents\source\MyBot\MyBot.csproj --project-dir F:\pablo\Documents\source\MyBot\ --root-namespace MyBot--language C# --framework net6.0 --nullable --working-dir F:\pablo\Documents\source\MyBot--verbose

Using assembly 'MyBot'.
Using startup assembly 'MyBot'.
Using application base 'F:\pablo\Documents\source\MyBot\bin\Debug\net6.0'.
Using working directory 'F:\pablo\Documents\source\MyBot'.
Using root namespace 'MyBot'.
Using project directory 'F:\pablo\Documents\source\MyBot\'.
Remaining arguments: .
Finding DbContext classes...
Finding IDesignTimeDbContextFactory implementations...
Found IDesignTimeDbContextFactory implementation 'MySqlContextFactory'.
Found DbContext 'MySqlContext'.
Finding application service provider in assembly 'MyBot'...
Finding Microsoft.Extensions.Hosting service provider...
No static method 'CreateHostBuilder(string[])' was found on class 'Program'.
No application service provider was found.
Finding DbContext classes in the project...
Using DbContext factory 'MySqlContextFactory'.
PS>

我认为我可以搜索的第一件事是 CreateHostBuilder 该工具搜索但不检索的功能。然而,再一次,我能找到的所有文档都是参考 ASP.NET 应用程序和我没有在我的机器人应用程序中实现的编程模式。我的应用程序确实通过定制的依赖注入检索服务(也许这就是 No application service provider was found. 行的原因?),但我没有找到一种方法来实现该 CreateHostBuilder 函数而不更改所有内容。

只是为了添加信息,这就是我使用非迁移方法设法创建和配置 EF 模型的方式:

public static IServiceProvider GetServices(DiscordSocketClient client, CommandService commands)
    {
        ServiceCollection services = new();

        services.AddSingleton(client);
        services.AddSingleton(commands);
        services.AddSingleton<HttpClient>();

        services.AddDbContext<MySqlContext>(ServiceLifetime.Scoped);

        return AddServices(services) // builds service provider;
    }

private static async Task InitDatabaseModel(IServiceProvider provider)
    {
        MySqlContext? dbCtxt = provider.GetService<MySqlContext>();

        if (dbCtxt == null)
        {
            Environment.Exit((int) EExitCodes.DB_SERVICE_UNAVAILABLE);
        }

        await dbContext.Database.EnsureDeletedAsync();
        await dbContext.Database.EnsureCreatedAsync();
    }

但不幸的是,我的应用程序计划与数据库动态交互,因此代码优先配置方法对我无效。

我该如何解决这个问题?是方法问题,还是我在搞乱自定义非 ASP.NET 依赖注入提供程序?谢谢大家

您的 IDesignTimeDbContextFactory 有问题。 EF Core 正在尝试为您的这个工厂创建一个 MySqlContext.

public class MySqlContextFactory : IDesignTimeDbContextFactory<MySqlContext>
{
    public MySqlContext CreateDbContext(string[] args)
    {
        // set up options
        DbContextOptionsBuilder optionsBuilder = new();
        ServerVersion mariaDbVersion = new MariaDbServerVersion(new Version(10, 6, 5));
        optionsBuilder.UseMySql(DatabaseCredentials.GetConnectionString(), mariaDbVersion);
        
        // *** this is the issue *** 
        // return default constructor W/O options (ie, UseMySql is never called)
        return new MySqlContext(); 
    }
}

您可以将此构造函数添加到您的 DbContext class:

public MySqlContext(DbContextOptions<MySqlContext> options)
        : base(options)
    {
    }

然后 return new MySqlContext(optionsBuilder.Options) 来自您的工厂。