kogonidze
kogonidze

Reputation: 157

How to configure Entity Framework in a separate project?

I have an ASP.NET MVC application EducationalCenter with the following structure of projects:

DbContext file is EducationalCenterContext.cs in the Data project and looks as follows:

public sealed class EducationalCenterContext: DbContext
{
    public DbSet<Student> Students { get; set; }

    public EducationalCenterContext( DbContextOptions<EducationalCenterContext> options)
        : base(options)
    {
        Database.EnsureCreated();
    }
}

And in Startup.cs file, the dbContext configured as follows in ConfigureService():

services.AddDbContext<EducationalCenterContext>
                (options => options.UseSqlServer("Server=localhost;Database=EducationalCenterDb;Trusted_Connection=True;MultipleActiveResultSets=true"));

This is my working version to which I came by fixing errors when try to add-migration. However it seems awful to me that my web app has project reference to the Data project.

What was my first idea:

In appsettings.json I created this section :

"ConnectionStrings": {
    "DefaultConnection":  "Server=localhost;Database=EducationalCenterDb;Trusted_Connection=True;MultipleActiveResultSets=true" 
}

Then I created AppSettings class in the Common project:

public class AppSettings
{
    public string ConnectionString { get; set; }
}

Then I try to pass ConnectionString in DAL via DI:

services.Configure<AppSettings>(Configuration.GetSection("ConnectionStrings"));

And created EducationalDbContext.cs:

public sealed class EducationalCenterContext: DbContext
{
    private readonly string _connectionString;

    public DbSet<Student> Students { get; set; }

    public EducationalCenterContext( IOptions<AppSettings>, DbContextOptions<EducationalCenterContext> options)
        : base(options)
    {
        _connectionString = app.Value.ConnectionString;
        Database.EnsureCreated();
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(_connectionString);
    }
} 

But when I try to add-migration via PM Console, I ran into this error:

Could not load assembly 'EducationalCenter.Data'. Ensure it is referenced by the startup project 'EducationalCenter'

Then I added project reference and ran into the next error:

Unable to create an object of type 'EducationalCenterContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728

Then I added services.AddDbContext<> in Startup.cs and came to the working version which I mentioned above.

So...

  1. Is it normal that my web app has reference to the data access project?
  2. Is it possible to configure EF in the Data project and ensure normal separation between DAL, BLL and web app?

Upvotes: 2

Views: 2471

Answers (1)

Neil W
Neil W

Reputation: 9122

Putting the context and configuration in a separate project is fine.

You got the first error because "Education Center" was set as start up project but did not have reference to data project.

The second error is because the migration builder needs some connection information in the data project to resolve the connection (to compare EF state and database state) to determine what changes are needed.

First add reference in your data project to:

Microsoft.EntityFrameworkCore.Design

Then add a context factory in your data project that migration console command will discover:

internal class MyContextFactory : IDesignTimeDbContextFactory<MyContext>
{
    public MyContext CreateDbContext(string[] args)
    {
        var dbContextBuilder = new DbContextOptionsBuilder<MyContext>();
        var connString = "myconnection string";
        dbContextBuilder.UseSqlServer(connString);
        return new MyContext(dbContextBuilder.Options);
    }
}

Upvotes: 3

Related Questions