Database.EnsureCreated 및 Database.Migrate를 어디에서 어떻게 호출합니까?


83

ASP.NET MVC 6 응용 프로그램이 Database.EnsureCreated있고 및 Database.Migrate메서드 를 호출해야 합니다.

하지만 어디로 전화해야합니까?


어느 쪽도 사용하고 싶지 않을 수 있습니다. MS 문서는 Migrate () 사용에 대해 이렇게 말합니다. "로컬 데이터베이스가있는 앱에는 좋지만 대부분의 애플리케이션은 SQL 스크립트 생성과 같은보다 강력한 배포 전략이 필요합니다." docs.microsoft.com/en-us/ef/core/managing-schemas/migrations
John Pankowicz

답변:


99

나는 이것이 중요한 질문이고 잘 대답되어야한다고 생각합니다!

Database.EnsureCreated 란 무엇입니까?

context.Database.EnsureCreated()컨텍스트에 대한 데이터베이스가 존재하는지 확인하는 새로운 EF 핵심 방법입니다. 존재하는 경우 조치가 수행되지 않습니다. 존재하지 않는 경우 데이터베이스와 모든 스키마가 생성되고이 컨텍스트의 모델과 호환되는지 확인합니다.

참고 : 이 방법은 마이그레이션을 사용하여 데이터베이스를 생성하지 않습니다. 또한 생성 된 데이터베이스는 나중에 마이그레이션을 사용하여 업데이트 할 수 없습니다. 관계형 데이터베이스를 대상으로하고 마이그레이션을 사용하는 DbContext.Database.Migrate()경우이 방법을 사용하여 데이터베이스가 생성되고 모든 마이그레이션이 적용되는지 확인할 수 있습니다 .

EF 6으로 어떻게 했습니까?

context.Database.EnsureCreated() EF 6의 아래 나열된 접근 방식과 동일합니다.

  1. 패키지 관리자 콘솔 :

    Enable-Migrations -EnableAutomaticMigrations. 추가 마이그레이션 / 업데이트 데이터베이스.

  2. 코드에서 :

    Database.SetInitializer CreateDatabaseIfNotExists

또는

DbMigrationsConfiguration을 사용하고 AutomaticMigrationsEnabled = true로 설정합니다.

Database.Migrate 란 무엇입니까?

컨텍스트에 대해 보류중인 마이그레이션을 데이터베이스에 적용합니다. 데이터베이스가없는 경우 생성합니다.

EF 6으로 어떻게 했습니까?

context.Database.Migrate() EF 6의 아래 나열된 접근 방식과 동일합니다.

  1. 패키지 관리자 콘솔 :

    업데이트-데이터베이스 -TargetMigration

  2. 사용자 지정 DbMigrationsConfiguration 사용 :

    AutomaticMigrationsEnabled = false; 또는 DbMigrator와 함께.

결론 :

마이그레이션을 사용하는 경우 context.Database.Migrate(). 마이그레이션을 원하지 않고 빠른 데이터베이스 (일반적으로 테스트 용) 만 원한다면 context.Database.EnsureCreated () / EnsureDeleted ()를 사용하십시오.


2
안녕하세요 Bassam Alugili, 답변 해 주셔서 감사합니다! 내 프로젝트에서 마이그레이션을 사용하고 있는데 두 방법을 함께 사용해서는 안된다는 것을 몰랐습니다.
bailando bailando

1
uw 및 여기에 호출하는 방법의 예가 있습니다! stefanhendriks.com/2016/04/29/...
바삼 Alugili에게

1
나는 Database.Migrate()creats 마이그레이션 (필요한 경우)이 기반 기반을 업데이트 한다고 생각 했습니다. EF 6의 자동 마이그레이션과 비슷합니다.하지만 제가 틀 렸습니다. 데이터베이스에서 기존 마이그레이션 (있는 경우) 만 적용합니다.
Afshar Mohebi

내가 이해하는대로 Database.Migrate는 DB를 삽입 / 쿼리 등을 수행 할 때 앱에서 사용하는 것과 동일한 DB 크레딧을 사용합니다. 생성 / 삭제 권한이있는 사용자가 이러한 작업을 수행하기를 원합니까? 이것은 Database.Migrate ()가 다른 크레딧 (생성 / 삭제 권한 포함)을 사용하도록하는 방법이 있습니까?
Ásgeir Gunnar Stefánsson

2
당신은 미래의 재난으로부터 나를 구해주었습니다. 명예
Shaswat Rungta

26

James P와 Bassam Alugili가 제공 한 정보를 사용하여 결국이 코드 줄을 클래스 ( Startup.cs ) 의 Configure메서드에 추가했습니다 .Startup

using (var scope = 
  app.ApplicationServices.CreateScope())
using (var context = scope.ServiceProvider.GetService<MyDbContext>())
    context.Database.Migrate();

이것이 바로 제가 찾던 것입니다. 대부분의 예제는 .Net 코어 또는 웹을 사용하며 .Net 4.6이 설치된 Windows Forms 응용 프로그램을 사용했습니다. 데이터베이스가 이미 만들어졌습니다 (연결 문자열의 사용자에게 데이터베이스를 만들 권한이 없기 때문). 그리고 위의 코드는 마이그레이션에서 모든 테이블과 모든 것을 생성했습니다.
nivs1978

16

앞서 언급 한 것처럼 Rowan Miller의 다음 내용을 읽어야 합니다 .

... EnsureCreated마이그레이션을 완전히 우회하고 스키마를 생성합니다. 마이그레이션과 혼합 할 수 없습니다. EnsureCreated매번 데이터베이스를 삭제하고 다시 생성해도 괜찮은 테스트 또는 신속한 프로토 타이핑을 위해 설계되었습니다. 마이그레이션을 사용 중이고 앱 시작시 자동으로 적용되도록하려면 context.Database.Migrate()대신 사용할 수 있습니다 .

대답에 따르면 여기 다음 항목에 추가 Globals.EnsureDatabaseCreated();해야합니다 Startup.cs.

시작 기능 Startup.cs의 :

public Startup(IHostingEnvironment env)
{
    // Set up configuration sources.
    var builder = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json")
            .AddEnvironmentVariables();

    if (env.IsDevelopment())
    {
        // This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.
            builder.AddApplicationInsightsSettings(developerMode: true);
    }
    Configuration = builder.Build();
    Globals.Configuration = Configuration;
    Globals.HostingEnvironment = env;
    Globals.EnsureDatabaseCreated();
}

그리고 다음 Globals.EnsureDatabaseCreated()과 같이 정의하십시오 .

public static void EnsureDatabaseCreated()
    {
        var optionsBuilder = new DbContextOptionsBuilder();
        if (HostingEnvironment.IsDevelopment()) optionsBuilder.UseSqlServer(Configuration["Data:dev:DataContext"]);
        else if (HostingEnvironment.IsStaging()) optionsBuilder.UseSqlServer(Configuration["Data:staging:DataContext"]);
        else if (HostingEnvironment.IsProduction()) optionsBuilder.UseSqlServer(Configuration["Data:live:DataContext"]);
        var context = new ApplicationContext(optionsBuilder.Options);
        context.Database.EnsureCreated();

        optionsBuilder = new DbContextOptionsBuilder();
        if (HostingEnvironment.IsDevelopment()) optionsBuilder.UseSqlServer(Configuration["Data:dev:TransientContext"]);
        else if (HostingEnvironment.IsStaging()) optionsBuilder.UseSqlServer(Configuration["Data:staging:TransientContext"]);
        else if (HostingEnvironment.IsProduction()) optionsBuilder.UseSqlServer(Configuration["Data:live:TransientContext"]);
        new TransientContext(optionsBuilder.Options).Database.EnsureCreated();
    }

사용하려면 여기 또는 여기를context.Database.Migrate() 참조 하십시오 .


안녕하세요 James, 답변 해주셔서 감사합니다!, 시작 방법에 유효한 Globals라는 이름에 대한 액세스 권한이 없습니다. 어떻게 액세스 할 수 있습니까?
bailando bailando

2
동일, Globals. 이것을 지렛대 노력의 비 - 표준 방법과 같은이 외모
더글러스 Gaskell

내가 이해하는 표준 방식은 DbContext가 Startup.ConfigureServices에서 생성되지만 일종의 간접 방법을 통해 생성된다는 것입니다. 거기에서 다시 낚시하거나 app.ApplicationServices.GetRequiredService <T>를 사용하여 Startup.Configure에서 낚시 할 수 있습니다. 나는 생각한다.
Josh Sutterfield

7

일반적으로는 다음과 같이 DbContext종속성 주입 컨테이너에 추가됩니다 Startup.ConfigureServices().

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        // Add DbContext to the injection container
        services.AddDbContext<MyDbContext>(options =>
                options.UseSqlServer(
                    this.Configuration.GetConnectionString("DefaultConnection")));
    }
}

그러나 IServiceCollection는 서비스 제공 업체로 작동하지 않으며은 현재 범위 이전에DbContext 주입 컨테이너에 등록되지 않았기 때문에 (Startup.ConfigureServices ) 되지 않았으므로 여기서 종속성 주입을 통해 컨텍스트에 액세스 할 수 없습니다.

Henk Mollema는 여기 에서 시작하는 동안 서비스를 수동으로 해결하는 방법에 대해 설명 하지만 다음과 같이 언급합니다.

서비스를 수동으로 해결 (서비스 로케이터라고도 함)하는 것은 일반적으로 안티 패턴으로 간주됩니다 . [그리고] 가능한 한 피해야합니다.

Henk는 또한 Startup생성자의 종속성 주입이 매우 제한적이며에서 구성된 서비스를 포함하지 않기 Startup.ConfigureServices()때문에 DbContext 사용이 앱의 나머지 부분에서 사용되는 주입 컨테이너를 통해 가장 쉽고 적절하다고 언급합니다.

런타임의 호스팅 서비스 공급자는 , ( 3.0 이전 버전) 및 .NET Startup과 같은 특정 서비스를 클래스 생성자에 삽입 할 수 있습니다 . 후자는 호스팅 계층에 의해 구축 된 인스턴스이며 애플리케이션을 시작하는 데 필요한 필수 서비스 만 포함합니다.IConfigurationIWebHostEnvironmentIHostingEnvironmentILoggerFactoryIServiceProvider

주문 전화에서 Database.EnsureCreated()또는 Database.Migrate(), 우리가 할 수있는, 그리고에 자동으로 DbContext의 결의를 갖고 싶어 Startup.Configure()우리의 구성 서비스는 DI를 통해 사용할 수있는 곳 :

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        // Add DbContext to the injection container
        services.AddDbContext<MyDbContext>(options =>
                options.UseSqlServer(
                    this.Configuration.GetConnectionString("DefaultConnection")));
    }

    public static void Configure(IApplicationBuilder app, IWebHostEnvironment env, MyDbContext context)
    {
        if (env.IsDevelopment())
        {
            context.Database.EnsureCreated();
            //context.Database.Migrate();
        }
    }
}

로 기억하십시오 바삼 Alugili의 대답 것을 EF 코어 문서에서 참조 Database.EnsureCreated()Database.Migrate()하나 개의 보장하지만 기존 마이그레이션이 필요한 경우 생성 된 데이터베이스에 적용되기 때문에 함께 사용되는 것은 아니다. 다른 하나는 데이터베이스가 존재하는지 확인하고 그렇지 않은 경우 DbContext컨텍스트에서 Fluent API를 통해 수행 된 시드를 포함하여 를 반영하는 데이터베이스를 생성합니다 .


1

또한 컨텍스트의 생성자에서 이것을 호출하면 성능 저하를 볼 수 있습니다 EnsureCreated. setup.cs 유틸리티로 이동 한 후 응답 시간이 크게 향상되었습니다.

참고 : EFC 및 UWP를 사용하고 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.