简体   繁体   English

在 Entity Framework Core 中自动创建数据库

[英]auto create database in Entity Framework Core

My application which is being ported to .NET core will use the new EF Core with SQLite.我正在移植到 .NET 核心的应用程序将使用带有 SQLite 的新 EF 核心。 I want to automatically create the database and table structures when the app is first run.我想在应用程序首次运行时自动创建数据库和表结构。 According to the EF core documentation this is done using manual commands根据 EF 核心文档,这是使用手动命令完成的

dotnet ef migrations add MyFirstMigration

dotnet ef database update

However I don't want the end user to enter these commands and would prefer to have the app create and setup the database for first use.但是,我不希望最终用户输入这些命令,而是希望应用程序创建和设置数据库以供首次使用。 For EF 6 there is functionality like对于 EF 6,有类似的功能

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

But in EF Core these don't seem to exist.但在 EF Core 中,这些似乎不存在。 I can't find any examples or documentation on something equivalent for EF core and it is not mentioned in the list of missing features in the EF core documentation.我找不到有关 EF 核心等效内容的任何示例或文档,并且在 EF 核心文档的缺失功能列表中未提及。 I have the model classes setup already so I could write some code to initialize the database based on the models but it would be heaps easier if the framework did this automatically.我已经设置了模型类,因此我可以编写一些代码来基于模型初始化数据库,但如果框架自动执行此操作会更容易。 I don't want to auto build the model or migrate, just create the table structures on a new database.我不想自动构建模型或迁移,只是在新数据库上创建表结构。

Am I missing something here or is auto create table function missing in EF core?我在这里遗漏了什么还是 EF 核心中缺少自动创建表功能?

If you have created the migrations, you could execute them in the Startup.cs as follows.如果您已经创建了迁移,您可以在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();
      }
      
      ...

This will create the database and the tables using your added migrations.这将使用您添加的迁移创建数据库和表。

If you're not using Entity Framework Migrations, and instead just need your DbContext model created exactly as it is in your context class at first run, then you can use:如果您不使用实体框架迁移,而只需要在首次运行时完全按照上下文类中的方式创建 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();
      }
      
      ...

Instead.反而。

If you need to delete your database prior to making sure it's created, call:如果您需要在确保创建数据库之前删除它,请调用:

            context.Database.EnsureDeleted();

Just before you call EnsureCreated()就在你打电话之前EnsureCreated()

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

My answer is very similar to Ricardo's answer, but I feel that my approach is a little more straightforward simply because there is so much going on in his using function that I'm not even sure how exactly it works on a lower level.我的回答与 Ricardo 的回答非常相似,但我觉得我的方法更简单一些,因为他的using函数中有很多事情发生,我什至不确定它在较低级别上究竟是如何工作的。

So for those who want a simple and clean solution that creates a database for you where you know exactly what is happening under the hood, this is for you:因此,对于那些想要一个简单而干净的解决方案来为您创建一个数据库的人,您可以在其中确切地知道幕后发生的事情,这适合您:

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

This pretty much means that within the DbContext that you created (in this case, mine is called TargetsContext ), you can use an instance of the DbContext to ensure that the tables defined with in the class are created when Startup.cs is run in your application.这几乎意味着在您创建的DbContext中(在这种情况下,我的称为TargetsContext ),您可以使用DbContext的实例来确保在类中定义的表在Startup.cs中运行时创建应用。

If you get the context via the parameter list of Configure in Startup.cs, You can instead do this:如果您通过 Startup.cs 中的 Configure 参数列表获取上下文,则可以改为执行以下操作:

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

For EF Core 2.0+ I had to take a different approach because they changed the API.对于 EF Core 2.0+,我不得不采取不同的方法,因为他们更改了 API。 As of March 2019 Microsoft recommends you put your database migration code in your application entry class but outside of the WebHost build code.截至 2019 年 3 月, Microsoft 建议您将数据库迁移代码放在应用程序入口类中,但放在 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>();
}

If you haven't created migrations, there are 2 options如果您尚未创建迁移,则有 2 个选项

1.create the database and tables from application Main: 1.从应用程序Main创建数据库和表:

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

2.create the tables if the database already exists: 2.如果数据库已经存在,则创建表:

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

Thanks to Bubi's answer感谢布比的回答

If you want both of EnsureCreated and Migrate use this code:如果您想要同时使用确保创建和迁移,请使用以下代码:

     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();
            }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM