Seeding EF Database in a Separate DAL Project

2019-06-14 07:26发布

问题:

I'm starting a new ASP.NET project, and I'm trying to follow the multi-project approach I've seen mentioned in multiple questions around Stackoverflow.

I've been following this tutorial, but it assumes only one project for your entire solution. Most notably, it recommends modifying your Global.asax file with code to set the database initializer.

Seeing as how my DAL project doesn't have a Global.asax file, what is the correct procedure for seeding the initial EF database?

回答1:

I stand corrected in my above comment that you would have access to the DAL by secondary reference. If you are truly wanting to keep from referencing the DAL in your web project, create a Bootstrapper class in your BLL that does the database stuff for you

The examples are pulled from the following blog post: http://weblogs.asp.net/rashid/archive/2009/02/17/use-bootstrapper-in-your-asp-net-mvc-application-and-reduce-code-smell.aspx

Create a bootstrap interface

public interface IBootstrapperTask
{
    void Execute();
}

Create a class that would handle your database configuration

public class InitializeDatabase : IBootstrapperTask
{
    public void Execute()
    {
        Database.SetInitializer(new Configuration());
        using (var db = new Context())
        {
          try
          {
            db.Database.Initialize(false);
          }
          catch (DataException ex)
          {

          }
          catch (Exception ex)
          {
            throw;
          }
        }
      }
       }

Create a static class that will execute the tasks (you can have more than one, registering routes could be moved to a BootstrapperTask)

public static class Bootstrapper
{
    static Bootstrapper()
    {
        ConfigureContainer();
    }

    public static void Run()
    {
        var tasks = ServiceLocator.Current.GetAllInstances<IBootstrapperTask>();

        foreach(var task in tasks)
        {
            task.Execute();
        }
    }

    private static void ConfigureContainer()
    {
        IUnityContainer container = new UnityContainer();

        UnityConfigurationSection configuration = (UnityConfigurationSection) ConfigurationManager.GetSection("unity");
        configuration.Containers.Default.Configure(container);

        ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(container));
    }
}

Finally, your global.asax would have a one liner

protected void Application_Start()
{
    Bootstrapper.Run();
}

There are some web.config things to do as well that you will see in the blog posting. Also, this question can lend some more information on the specifics of disposing, etc. There are more benefits to boostrapping than simply not having to reference a DAL with some excellent posts around the community on why using this pattern is a good thing as well as a few different approaches on implementation.



回答2:

In the Application_Start of the Global.asax:

Database.SetInitializer(new Configuration());
using (var db = new Context())
{
    try
    {
        db.Database.Initialize(false);
    }
    catch (DataException ex)
    {

    }
    catch (Exception ex)
    {
        throw;
    }
}

Where the Context class lives in the DAL:

public class Context : DbContext
{
    public Context() : base("YourDatabaseName") { }
    public DbSet<Employee> Employees { get; set; }

    // ...

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new EmployeeMap()); 

You do the mapping in a dedicated class public class EmployeeMap : EntityTypeConfiguration<Employee>.

Seeding is done in the DAL:

public sealed class Configuration : DropCreateDatabaseAlways<Context>
{
    protected override void Seed(Context context)
    {
        // Do your seeding here
    }
}