如何在第一次运行时自动创建数据库?

我的应用程序被移植到。NET 核心将与 SQLite 一起使用 EF 核心。我想自动创建数据库和表时,应用程序首次运行。根据文档记载,这是通过手动命令完成的:

dotnet ef migrations add MyFirstMigration


dotnet ef database update

我不希望最终用户输入这些,但更喜欢应用程序创建和设置数据库的第一次使用。对于 EF6而言,有以下几点:

Database.SetInitializer(new CreateDatabaseIfNotExists<MyContext>());

但我找不到任何类似 EF Core 的产品。我已经有了模型类,所以我可以编写代码来初始化基于模型的数据库,但是如果框架自动完成这项工作会更容易。我不想自动构建模型或迁移,只是在一个新的数据库中创建表。

EF Core 是否缺少自动创建表的功能?

158634 次浏览

如果您已经创建了迁移,那么您可以在 Startup.cs中执行它们,如下所示。

 public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
{
var context = serviceScope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
context.Database.Migrate();
}
      

...

这将使用添加的迁移创建数据库和表。

如果您不使用实体框架迁移,而只是需要在第一次运行时完全按照上下文类创建 DbContext 模型,那么您可以使用:

 public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
{
var context = serviceScope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
context.Database.EnsureCreated();
}
      

...

相反。

如果需要在确保创建数据库之前删除数据库,请调用:

context.Database.EnsureDeleted();

在你打电话给 EnsureCreated()之前

改编自: http://docs.identityserver.io/en/latest/quickstarts/7_entity_framework.html?highlight=entity

我的答案与 Ricardo 的答案非常相似,但我觉得我的方法更简单一些,因为他的 using函数中有太多的东西,我甚至不确定它在较低层次上是如何工作的。

因此,对于那些想要一个简单而干净的解决方案,为您创建一个数据库,在那里您可以准确地知道在引擎盖下发生了什么的人,这是为您准备的:

public Startup(IHostingEnvironment env)
{
using (var client = new TargetsContext())
{
client.Database.EnsureCreated();
}
}

这意味着在您创建的 DbContext中(在本例中,我的 TargetsContext) ,您可以使用 DbContext的一个实例来确保在应用程序中运行 Startup.cs时创建类中定义的表。

如果您还没有创建迁移,有两个选项

1. 从应用程序 Main 中创建数据库和表:

var context = services.GetRequiredService<YourRepository>();
context.Database.EnsureCreated();

2. 如果数据库已经存在,则创建表:

var context = services.GetRequiredService<YourRepository>();
context.Database.EnsureCreated();
RelationalDatabaseCreator databaseCreator =
(RelationalDatabaseCreator)context.Database.GetService<IDatabaseCreator>();
databaseCreator.CreateTables();

多亏了 Bubi 的 回答

如果通过 Startup.cs 中的 Configure 参数列表获取上下文,则可以这样做:

public void Configure(IApplicationBuilder app, IHostingEnvironment env,  LoggerFactory loggerFactory,
ApplicationDbContext context)
{
context.Database.Migrate();
...

对于 EF Core 2.0 + ,我不得不采取一种不同的方法,因为他们改变了 API。从2019年3月开始,微软建议将数据库迁移代码放在应用程序条目类中,但是放在 WebHost 构建代码之外。

public class Program
{
public static void Main(string[] args)
{
var host = CreateWebHostBuilder(args).Build();
using (var serviceScope = host.Services.CreateScope())
{
var context = serviceScope.ServiceProvider.GetRequiredService<PersonContext>();
context.Database.Migrate();
}
host.Run();
}


public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}

如果您希望同时使用 EnsureCreated 和 Migrate,请使用以下代码:

     using (var context = new YourDbContext())
{
if (context.Database.EnsureCreated())
{
//auto migration when database created first time


//add migration history table


string createEFMigrationsHistoryCommand = $@"
USE [{context.Database.GetDbConnection().Database}];
SET ANSI_NULLS ON;
SET QUOTED_IDENTIFIER ON;
CREATE TABLE [dbo].[__EFMigrationsHistory](
[MigrationId] [nvarchar](150) NOT NULL,
[ProductVersion] [nvarchar](32) NOT NULL,
CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY CLUSTERED
(
[MigrationId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY];
";
context.Database.ExecuteSqlRaw(createEFMigrationsHistoryCommand);


//insert all of migrations
var dbAssebmly = context.GetType().GetAssembly();
foreach (var item in dbAssebmly.GetTypes())
{
if (item.BaseType == typeof(Migration))
{
string migrationName = item.GetCustomAttributes<MigrationAttribute>().First().Id;
var version = typeof(Migration).Assembly.GetName().Version;
string efVersion = $"{version.Major}.{version.Minor}.{version.Build}";
context.Database.ExecuteSqlRaw("INSERT INTO __EFMigrationsHistory(MigrationId,ProductVersion) VALUES ({0},{1})", migrationName, efVersion);
}
}
}
context.Database.Migrate();
}