我已阅读 Design-time DbContext Creation EF Core 工具(例如,迁移命令)有 3 种方式获取派生 DbContext
在设计时而不是在运行时从应用程序实例。
- 来自应用程序服务提供商
- 来自任何无参数构造函数
- 来自实现
IDesignTimeDbContextFactory<T>
的类
这里我只对第一种方法感兴趣,模仿Asp.net Core中使用的模式。这段代码无法编译,因为我不知道如何让 EF Core 工具获得 TheContext
实例。
最小工作示例
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.IO;
public class TheContext : DbContext
{
public TheContext(DbContextOptions<TheContext> options) : base(options) { }
public DbSet<User> Users { get; set; }
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
class Program
{
private static readonly IConfiguration _configuration;
private static readonly string _connectionString;
static Program()
{
_configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true).Build();
_connectionString = _configuration.GetConnectionString("SqlServer");
}
static void ConfigureServices(IServiceCollection isc)
{
isc.AddSingleton(_ => _configuration);
isc.AddDbContextPool<TheContext>(options => options
.UseSqlServer(_connectionString));
isc.AddSingleton<TheApp>();
}
static void Main()
{
IServiceCollection isc = new ServiceCollection();
ConfigureServices(isc);
IServiceProvider isp = isc.BuildServiceProvider();
isp.GetService<TheApp>().Run();
}
}
class TheApp
{
readonly TheContext _theContext;
public TheApp(TheContext theContext) => _theContext = theContext;
public void Run()
{
// Do something on _theContext
}
}
问题
如何让 EF Core 工具从控制台应用程序的服务提供者处获取 DbContext 实例?
编辑:
我忘了提到 appsettings.json
如下:
{
"ConnectionStrings": {
"Sqlite": "Data Source=MyDatabase.db",
"SqlServer": "Server=(localdb)\\mssqllocaldb;Database=MyDatabase;Trusted_Connection=True"
}
}
最佳答案
虽然文档主题叫做From application services , 它开始于
If your startup project is an ASP.NET Core app, the tools try to obtain the DbContext object from the application's service provider.
看起来他们不希望 ASP.NET Core 应用程序以外的项目类型使用应用程序服务提供者:)
然后继续
The tools first try to obtain the service provider by invoking Program.BuildWebHost() and accessing the IWebHost.Services property.
和example :
public static IWebHost BuildWebHost(string[] args) => ...
这是适用于当前 (EF Core 2.1.3) 位的技巧。这些工具实际上是在包含您的入口点(通常是 Program
)的类中搜索名为 BuildWebHost
和 string[] 的静态(不需要公开)方法args
参数,以及重要的未记录部分 - 返回类型 不需要 IWebHost
!它可以是像这样具有公共(public)属性的任何对象
public IServiceProvider Services { get; }
这给了我们以下解决方案:
class Program
{
// ...
// Helper method for both Main and BuildWebHost
static IServiceProvider BuildServiceProvider(string[] args)
{
IServiceCollection isc = new ServiceCollection();
ConfigureServices(isc);
return isc.BuildServiceProvider();
}
static void Main(string[] args)
{
BuildServiceProvider(args).GetService<TheApp>().Run();
}
// This "WebHost" will be used by EF Core design time tools :)
static object BuildWebHost(string[] args) =>
new { Services = BuildServiceProvider(args) };
}
更新:从 v2.1 开始,您还可以使用新的 CreateWebHostBuilder
模式,但恕我直言,它只是增加了这里不需要的另一层复杂性(仍然支持以前的模式)。它是相似的,但现在我们需要一个名为 CreateWebHostBuilder
的方法,它返回一个具有公共(public)方法 Build()
的对象,返回具有公共(public) Services
属性的对象,返回 IServiceProvider
。为了在 Main
中被重用,我们不能使用匿名类型并且必须创建 2 个类,这也使得它在 Main
中的使用更加冗长:
class AppServiceBuilder
{
public ServiceCollection Services { get; } = new ServiceCollection();
public AppServiceProvider Build() => new AppServiceProvider(Services.BuildServiceProvider());
}
class AppServiceProvider
{
public AppServiceProvider(IServiceProvider services) { Services = services; }
public IServiceProvider Services { get; }
}
class Program
{
// ...
static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Services.GetService<TheApp>().Run();
}
// This "WebHostBuilder" will be used by EF Core design time tools :)
static AppServiceBuilder CreateWebHostBuilder(string[] args)
{
var builder = new AppServiceBuilder();
ConfigureServices(builder.Services);
return builder;
}
}
关于c# - 如何使 EF Core 工具从控制台应用程序的服务提供者处获取 DbContext 实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52511960/