注意 我已经阅读了大量看似相似的SO答案,但是我已经按照他们的建议去做,所以我没有知道WPF是否有区别(它们似乎都与ASP.NET有关)。另外,大多数答案都与运行时错误有关,而不是添加迁移时的错误。
我正在尝试建立一个使用EntityFrameWork Core的.NET Core 3 WPF项目,但是在添加迁移时遇到了问题。我将上下文设置如下...
public class ApplicationDbContext : DbContext {
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options) {
}
public ApplicationDbContext() {
}
public DbSet<Product> Products { get; set; }
}
无参数构造函数在那里,因为没有它,我会得到一个异常在尝试添加迁移时无法创建类型为'ApplicationDbContext'的对象。
我的App.xaml.cs
包含以下内容...
public partial class App {
public IServiceProvider ServiceProvider { get; private set; }
public IConfiguration Configuration { get; private set; }
protected override void OnStartup(StartupEventArgs e) {
IConfigurationBuilder builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appSettings.json", optional: false, reloadOnChange: true);
Configuration = builder.Build();
ServiceCollection serviceCollection = new ServiceCollection();
ConfigureServices(serviceCollection);
ServiceProvider = serviceCollection.BuildServiceProvider();
MainWindow mainWindow = ServiceProvider.GetRequiredService<MainWindow>();
mainWindow.Show();
}
private void ConfigureServices(IServiceCollection services) {
// Configuration
services.Configure<AppSettings>(Configuration.GetSection(nameof(AppSettings)));
// Database
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("SqlConnection")));
// Windows
services.AddTransient(typeof(MainWindow));
}
}
我意识到其中的某些内容是无关紧要的,但我想我会向全班同学展示,以防万一它揭示了我错过的内容。该代码基于此blog post。
但是,当我尝试添加迁移时,出现异常“ 没有为此DbContext配置数据库提供程序。可以通过覆盖DbContext.OnConfiguring方法或在应用程序上使用AddDbContext来配置提供程序。服务提供者。如果使用AddDbContext,则还要确保您的DbContext类型在其构造函数中接受DbContextOptions对象,并将其传递给DbContext的基本构造函数。“
据我所知,我已经配置了数据库提供程序。我在ConfigureServices
方法中设置了一个断点,可以看到使用正确的连接字符串调用了services.AddDbContext
。
有人知道我错过了什么吗?
更新,我尝试连接到现有数据库,并且运行良好,因此看来数据库提供程序已正确配置。只有当我尝试添加迁移时,我才例外。
更新2 似乎迁移工具正在上下文中使用无参数构造函数,这就是为什么它认为尚未配置提供程序的原因。如果我从App.xaml.cs中删除对其进行配置的行,而改写OnConfiguring
方法来调用UseSqlServer
,则迁移可以正常进行。但是,除了我没有看到其他人这样做的事实(这使我想知道这是否真的是正确的方法)之外,我没有看到如何从配置文件中获取连接字符串。我无法注入IConfiguration
参数,因为整个问题是迁移需要无参数的构造函数。
答案 0 :(得分:1)
使用 .Net Core 3.1 和 EF Core Version 5 实际上很简单,Entity Framework 将查看静态函数 CreateHostBuilder
的入口点类,在我的情况下是 App
类在 app.xaml.cs 中。
不完全确定 .Net Core 3.1 之前所需的约定。根据我的经验,它与使用 .Net Core 2.1 和 ASP.Net 的 Startup 类有关。
https://docs.microsoft.com/en-us/ef/core/cli/dbcontext-creation?tabs=dotnet-core-cli
我的解决方案:
public partial class App : Application
{
/// <summary>
/// Necessary for EF core to be able to find and construct
/// the DB context.
/// </summary>
public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
// Configure Application services
.ConfigureServices((context, services) =>
{
ConfigureServices(context, services);
});
}
/// <summary>
/// Not necessary but I prefer having a separate function for
/// configuring services.
/// </summary>
private static void ConfigureServices(HostBuilderContext context, IServiceCollection services)
{
...
}
/// <summary>
/// Hold the built Host for starting and stopping
/// </summary>
private readonly IHost AppHost;
/// <summary>
/// Constructor
/// </summary>
public App()
{
// Create Application host
AppHost = CreateHostBuilder(new string[] { }).Build();
}
/// <summary>
/// App Startup Event Handler
/// </summary>
private async void Application_Startup(object sender, StartupEventArgs e)
{
// Start the application host
await AppHost.StartAsync();
...
}
/// <summary>
/// App Exit Event Handler
/// </summary>
private async void Application_Exit(object sender, ExitEventArgs e)
{
// Kill the application host gracefully
await AppHost.StopAsync(TimeSpan.FromSeconds(5));
// Dispose of the host at the end of execution
AppHost.Dispose();
}
}
答案 1 :(得分:0)
您需要实现IDesignTimeDbContextFactory
。 ASP.NET Core应用程序中有很多隐藏的管道,用于连接应用程序服务提供商,因此可以通过dotnet ef
工具找到它,但是WPF中没有这样的管道。此外,ef工具对WPF事件一无所知,因此您的OnStartup
方法甚至不会被调用(甚至不会创建该类的实例)来创建DI设置,以便ef工具可以找到您的DBContext
将创建ServiceProvider
的代码移到构造函数中,而不是查找并显示主窗口的代码。
实施IDesignTimeDbContextFactory<ApplicationDbContext>
。在已实现的CreateDbContext
方法return ServiceProvider.GetRequiredService<ApplicationDbContext>()
然后,该工具将创建您的类的实例,该实例将设置DI,并调用该方法以获取(现已配置)数据库上下文,并且该方法应该可以工作。
我还建议您转到基于HostBuilder
的配置(该博客文章是在发布Core 3最终版本之前编写的)。您将找到同一帖子here