Program Club

Entity Framework CodeFirst를 사용하여 데이터베이스를 시드하려면 어떻게해야합니까?

proclub 2020. 11. 28. 12:47
반응형

Entity Framework CodeFirst를 사용하여 데이터베이스를 시드하려면 어떻게해야합니까?


데이터베이스가 성공적으로 생성되었지만 (테이블과 마찬가지로) 시드되지 않았습니다. 나는 몇 시간을 보냈고 수많은 기사를 읽었지만 그것을 얻을 수 없었습니다. 어떤 제안?

참고로 클라이언트에서 내 DatabaseContext에 대한 참조없이 이니셜 라이저를 호출 할 수 있습니까?

내가 생각할 수있는 모든 관련 코드를 포함했습니다. 다른 도움이 필요하면 알려주세요.

내가 시도한 것 :

  1. 내 연결 문자열을 삭제했습니다 (기본값은 sqlexpress이므로 이름 만 변경됨)
  2. DropCreateDatabaseIfModelChanges를 DropCreateDatabaseAlways로 변경했지만 여전히 동일합니다.

편집 : 정말 이상한 것은 한 번 작동했지만 어떻게 또는 왜 다시 끊어 졌는지 모르겠습니다. 나는 연결 문자열을 가정하고 있지만 누가 압니다.

DatabaseInitializer.cs

public class DatabaseInitializer : DropCreateDatabaseIfModelChanges<DatabaseContext>
{
  protected override void Seed(DatabaseContext context)
  {
    // Seeding data here
    context.SaveChanges();
  }
}

DatabaseContext.cs

public class DatabaseContext : DbContext
{
  protected override void OnModelCreating(DbModelBuilder mb)
  {
    // Random mapping code
  }

  public DbSet<Entity1> Entities1 { get; set; }
  public DbSet<Entity2> Entities2 { get; set; }

}

Global.asax.cs-Application_Start ()

protected void Application_Start()
{
  Database.SetInitializer<DatabaseContext>(new DatabaseInitializer());
  AreaRegistration.RegisterAllAreas();
  RegisterGlobalFilters(GlobalFilters.Filters);
  RegisterRoutes(RouteTable.Routes);
}

클라이언트 web.config

<connectionStrings>
  <add name="DatabaseContext" connectionString="data source=.\SQLEXPRESS;Database=Database;Integrated Security=SSPI;" providerName="System.Data.SqlClient" />
</connectionStrings>

해결책

문서화를 위해 여기에서 솔루션을 공유하고 있습니다. 모든 댓글을 탐색하는 것은 어쨌든 고통 스러울 것입니다. 결국에는 별도의 클래스에 DatabaseInitializer와 DatabaseContext가 있습니다. 이 작은 변화가 그것을 고치는 동안 나는 정말로 이해하지 못하지만 여기 있습니다.

DatabaseInitializer.cs

public class DatabaseInitializer : CreateDatabaseIfNotExists<DatabaseContext>
{
  protected override void Seed(DatabaseContext context)
  {
    // Seed code here
  }
}

DatabaseContext.cs

public class DatabaseContext : DbContext
{
  public DatabaseContext() : base("MyDatabase") { }

  protected override void OnModelCreating(DbModelBuilder mb)
  {
    // Code here
  }

  public DbSet<Entity> Entities { get; set; }
  // Other DbSets
}

Global.asax.cs-Application_Start ()

protected void Application_Start()
{
  Database.SetInitializer(new DatabaseInitializer());
  AreaRegistration.RegisterAllAreas();
  RegisterGlobalFilters(GlobalFilters.Filters);
  RegisterRoutes(RouteTable.Routes);
}

이것은 내 DbContext 클래스가 모두 어떻게 생겼으며 제대로 시드됩니다.

public class MyDbContext : DbContext
{
    public DbSet<MyClass> MyClasses { get; set; }

    protected override void OnModelCreating (DbModelBuilder modelBuilder)
    {
        base.OnModelCreating (modelBuilder);
        modelBuilder.Conventions.Remove<System.Data.Entity.ModelConfiguration.Conventions.PluralizingTableNameConvention> ();

        // Add any configuration or mapping stuff here
    }

    public void Seed (MyDbContext Context)
    {
        #if DEBUG
        // Create my debug (testing) objects here
        var TestMyClass = new MyClass () { ... };
        Context.MyClasses.Add (TestMyClass);
        #endif

        // Normal seeding goes here

        Context.SaveChanges ();
    }

    public class DropCreateIfChangeInitializer : DropCreateDatabaseIfModelChanges<MyDbContext>
    {
        protected override void Seed (MyDbContext context)
        {
            context.Seed (context);

            base.Seed (context);
        }
    }

    public class CreateInitializer : CreateDatabaseIfNotExists<MyDbContext>
    {
        protected override void Seed (MyDbContext context)
        {
            context.Seed (context);

            base.Seed (context);
        }
    }

    static MyDbContext ()
    {
        #if DEBUG
        Database.SetInitializer<MyDbContext> (new DropCreateIfChangeInitializer ());
        #else
        Database.SetInitializer<MyDbContext> (new CreateInitializer ());
        #endif
    }
}

나는이 패턴을 몇 번 사용했고 그것은 나를 위해 아주 잘 작동했다.


in에 대한 Seed적절한 호출로도 메서드가 호출되지 않았습니다 . 그 이유는 정말 간단했습니다. 실제로 데이터베이스 컨텍스트를 사용 하는 코드가없는 경우 이니셜 라이저가 전혀 호출되지 않을 수 있습니다 .Database.SetInitializerApplication_Start


이것은 나의 슬픈 작은 이야기입니다.

첫째, 교훈 :

  1. 시드 메서드는 컨텍스트가 사용될 때까지 호출되지 않습니다.
  2. Global.asax.cs는 디버거가 연결되기 전에 실행되는 첫 번째 실행 bc에서 중단 점에 도달하지 않습니다. Global.asax.cs에서 중단 점에 도달하려면 Web.config에 공백을 추가하고 페이지를 입력해야합니다. 그러면 맞을 것입니다.
  3. db에 대한 VS 연결이 있으면 시드가 발생하지 않습니다. 앱에서 오류가 발생합니다.

따라서 슬픔을 피하려면 :

  • VS 연결을 끊습니다.
  • 기본 클래스 DropCreateDatabaseAlways를 한 번에 전환합니다.
  • 컨텍스트를 사용하는 페이지를 누르십시오.

자, 슬픔 :

  1. 내 Global.asax.cs 파일에 사용자 지정 Initializer 클래스가 있습니다. 내 Initializer Seed 메서드에 중단 점이 있습니다. 나는 응용 프로그램을 시작했고 그 방법은 결코 맞지 않았습니다. :(
  2. Application_Start의 Database.SetInitializer 호출에서 중단 점을 가리 킵니다. 맞지 않았습니다. :(
  3. I realized that I had no db schema changes, so then I changed DropCreateDatabaseIfModelChanges to DropCreateDatabaseAlways. Still, nothing. :(
  4. I finally went to a page that uses the context, and it worked. :/

You can call update-database to manually run the seed method inside the Configuration class. This requires enable-migrations to be on as well.

PM> update-database
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
No pending code-based migrations.
Running Seed method.

internal sealed class Configuration : DbMigrationsConfiguration<ProjectManager.Data.Database.ProjectDb>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
    }

    protected override void Seed(ProjectManager.Data.Database.ProjectDb context)
    {
        context.Status.AddOrUpdate(
            new Status() { Id = 1, Text = "New" },
            new Status() { Id = 2, Text = "Working" },
            new Status() { Id = 3, Text = "Completed" },
            new Status() { Id = 4, Text = "Skipped" }
        );
    }
}

The following change in the Global.asax file worked for me:

Old Code:

    protected void Application_Start()
    {
        Database.SetInitializer<mycontextclassname>(new DropCreateDatabaseAlways<mycontextclassname>());             
       ...
    }

New Code:

    protected void Application_Start()
    {
        Database.SetInitializer<mycontextclassname>(new DropCreateDatabaseAlways<mycontextclassname>()); 
        Database.SetInitializer(new Initializer()); 
        ...
    }

I too have had difficulty getting Seed() to be invoked. And I do appreciate all the helpful suggestions above and have had some luck using DropCreateDatabaseAlways ... but not ALWAYS!!

Most recently, I added the following line of code in the the constructor of my Repository to good effect:

    public CatalogRepository()
    {
        _formCatalog.FormDescriptors.GetType();

    }

It was sufficient to trigger the Seed() getting invoked. If you've tried everything above this answer and still no luck, give it a try. Good luck this was really a time consuming experience.


The seed event in your example will only be fired once as your using DropCreateDatabaseIfModelChanges you can change this to DropCreateDatabaseAlways i think and it should fire the seed event every time.

Edit

This is my DataContext

public WebContext()
{   
    DbDatabase.SetInitializer(new DropCreateDatabaseIfModelChanges<WebContext>());
}

This just happened to me while I was discovering Code First Features. This situation often happens when you have first used Code First to generate your database without any initialization strategy.

If you decide to do so later on by implementing a DropCreateDatabaseIfModelChanges based strategy, but without modifying you model, then your Seed method won't be called since the database generation and your strategy will only be applied next time you change your model.

If this happens to you, just try to modify your model a bit to test this hypothesis and I bet, your database is going to be populated ;)

I don't have the solution yet, except using a strategy that always generate the database, but I'm really not confortable with the fact of putting the initialization strategy in your DbContext since this class is goind to be used in you production environement, althought the initialization strategy seems to be mostly used for fluent developement environnement.


I've just come across this problem. I've deleted the "connectionstrings" section from the Web.config file, and currently the app started running - without the connectionstrings section! I add the section back, and the database is not seeding again. It's not a proper solution, but I'm just adding a data point here to what can potentially solve the problem.

Fortunately it's just a small "throwaway" app I'll discard soon anyway ...


Meticulously ensure that you didn't declare your context variable more than once. If you declare it again after seeding, the seed will be overwritten.


I was having same problem and after change in both Global.asax file and Intializer file it worked. I hope it will work for those who are still having problem for data seeding.

New Code in Global.asax:

    protected void Application_Start()
    {
        Database.SetInitializer<mycontextclassname>(new DropCreateDatabaseAlways<mycontextclassname>()); 
        Database.SetInitializer(new Initializer()); 
        ...
    }

code for Intializer file:

public class Initializer : System.Data.Entity.DropCreateDatabaseAlways<Context>

Updated to note that this answer is incorrect! The reason for my DB not getting seeded remains a mystery (but it wasn't the lack of a default base constructor call, as noted by @JaredReisinger)

I appreciate this question is a little old but I ended up here so someone else might. Here's my tuppence worth:

My DB was getting created fine but not seeded, even if I deleted the database and started again using DropDatabaseInitialiser.

After reading the code above I noticed that my context constructor was this

public MyApp_Context()
{
    // some code
}

whereas the example above would be as follows for my setup

public MyApp_Context() : base("name=MyApp_Context")
{
    // some code
}

Yup, I wasn't calling the base object's constructor! I wouldn't have expected everything except seeding to work in this instance but that appears to be the (repeatable) case.

NB, I don't actually need to supply the context name in the base constructor call; I only wrote it that way initially because I was copying the format of the solution above. So my code is now this, and seeding works on initial database creation.

public MyApp_Context() : base()
{
    // some code
}

참고URL : https://stackoverflow.com/questions/6312336/how-can-i-get-my-database-to-seed-using-entity-framework-codefirst

반응형