Seed initial data in Entity Framework 7 RC 1 and ASP.NET MVC 6 [duplicate]
Asked Answered
V

5

17

It seems that in Entity Framework 7 there is no native support for seed data yet (https://github.com/aspnet/EntityFramework/issues/629).

There is no DbMigrationsConfiguration class, no Seed method in the template code provided by Microsoft.

So how to seed data in ASP.NET MVC 6 web application that uses Entity Framework 7 RC 1?

Virtuoso answered 30/12, 2015 at 19:34 Comment(1)
You can also see this article in MSDN blogs: blogs.msdn.microsoft.com/dotnet/2016/09/29/…Virtuoso
V
15

I've found a temporary workaround for myself.

We can create a method SeedData that extends the IApplicationBuilder then gets an instance of our database context class through GetService method and uses it for seeding the data.

Here is how my extension method looks like:

using Microsoft.AspNet.Builder;
using Microsoft.Extensions.DependencyInjection;

public static class DataSeeder
{
    // TODO: Move this code when seed data is implemented in EF 7

    /// <summary>
    /// This is a workaround for missing seed data functionality in EF 7.0-rc1
    /// More info: https://github.com/aspnet/EntityFramework/issues/629
    /// </summary>
    /// <param name="app">
    /// An instance that provides the mechanisms to get instance of the database context.
    /// </param>
    public static void SeedData(this IApplicationBuilder app)
    {
        var db = app.ApplicationServices.GetService<ApplicationDbContext>();

        // TODO: Add seed logic here

        db.SaveChanges();
    }
}

To use it put app.SeedData(); line in the Configure method of the application Startup class (located in the web project in file called Startup.cs).

// This method gets called by the runtime.
// Use this method to configure the HTTP request pipeline.
public void Configure(
    IApplicationBuilder app,
    IHostingEnvironment env,
    ILoggerFactory loggerFactory)
{
    app.SeedData();

    // Other configuration code
}
Virtuoso answered 30/12, 2015 at 19:34 Comment(1)
This might be why I am receiving those debug messages when I did my initial migrations!Encroach
A
6

For EF Core RTM 1.0 and ASP.NET Core RTM 1.0

First create the seed method. Here because we are out the scope of the current request, we must create it manulally:

using System.Collections.Generic;
using System.Linq;
using Core1RtmEmptyTest.Entities;
using Microsoft.Extensions.DependencyInjection;

namespace Core1RtmEmptyTest.Migrations
{
    public static class ApplicationDbContextSeedData
    {
        public static void SeedData(this IServiceScopeFactory scopeFactory)
        {
            using (var serviceScope = scopeFactory.CreateScope())
            {
                var context = serviceScope.ServiceProvider.GetService<ApplicationDbContext>();
                if (!context.Persons.Any())
                {
                    var persons = new List<Person>
                    {
                        new Person
                        {
                            FirstName = "Admin",
                            LastName = "User"
                        }
                    };
                    context.AddRange(persons);
                    context.SaveChanges();
                }
            }

        }
    }
}

Then specify the correct life time of the ApplicationDbContext

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(ServiceLifetime.Scoped);

And finally call the SeedData() method from the Configure method

public void Configure(IServiceScopeFactory scopeFactory)
{
    scopeFactory.SeedData();
According answered 16/8, 2016 at 6:26 Comment(0)
R
2

I have created private Seed() method in my Startup.cs but I also like your approach because it can be used not only during application startup.

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    this.Seed();
}

private void Seed()
{
    using (var db = new MyDbContext())
    {
        db.Database.Migrate();

        // Seed code

        db.SaveChanges();
    }
}
Romanist answered 30/12, 2015 at 21:25 Comment(0)
C
2

From EF/MVC intro, just :

  1. dependency-inject your DbContext (SchoolContext below) directly into Startup.Configure()*
  2. pass your DbContext to a function (DbInitializer.Initialize below) which does something like:
    1. ensure Database is created or that it's migrated; context.Database.EnsureCreated(); consider context.Database.Migrate();
    2. returns if already seeded if (context.Students.Any()) { return; }
    3. else seed context.Students.Add({...}); context.SaveChanges();

Like here:

public void Configure(..., ..., SchoolContext context)
{

    ...
    DbInitializer.Initialize(context);
}

...

public static class DbInitializer
{
    public static void Initialize(SchoolContext context)
    {
        context.Database.EnsureCreated();

        // Look for any students.
        if (context.Students.Any())
        {
            return;   // DB has been seeded
        }

        var students = new Student[]
        {
            new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2005-09-01")}, ...
        };
        foreach (Student s in students)
        {
            context.Students.Add(s);
        }
        context.SaveChanges();
        ...

*Dependency-injecting into Startup.Configure() is why my answer is worthy (even though another answer is already accepted.)

  1. Dependency-injecting your DbContext into Startup.Configure() is done in EF/MVC Intro
  2. No other answer here just dependency-injects into Configure; they either GetService() and/or GetRequiredService(), or instantiate a new DbContext. You may not need that much code. Then again, you may need that much code, (i.e. if the Dependency-Injected DbContext was disposed, which is where the GetService() is necessary to create a new Scope.. Please downvote/edit/comment if I'm mistaken about something.
Cicisbeo answered 25/5, 2017 at 3:16 Comment(0)
L
1

You can create the static seed method inside the ApplicationDbContext and passing IApplicationBuilder as a parameter. Then call this method in the Startup.cs.

    public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }


    public static void Seed(IApplicationBuilder applicationBuilder)
    {
        using (var context=applicationBuilder.ApplicationServices.GetRequiredService<ApplicationDbContext>())
        {
            context.Database.EnsureDeleted();
            context.Database.EnsureCreated();
            for(int i = 1; i< 1000; i++)
            {
                context.Movies.Add(new Movie
                {
                   Genre = "Action",
                   ReleaseDate =DateTime.Today,
                   Title = "Movie "+i
                });
            }
            context.SaveChanges();
        }
    }

    public DbSet<Movie> Movies { get; set; }
}

In Configure() method inside Startup.cs, call the ApplicationDbContext.Seed(app)

      public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
            app.UseBrowserLink();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }

        app.UseStaticFiles();

        app.UseIdentity();


        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
        ApplicationDbContext.Seed(app);
    }
Levine answered 25/10, 2016 at 4:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.