Skip to content

Allow a second type argument AddDbContext to support inheritance #10451

@Flexba

Description

@Flexba

I have a project running in different environments with different databases (PostgreSQL / SQL Server). I tried using the same DbContext for both databases but had some problems with migrations since vendor specific code is added (e.g. data types).

I decided to make two distinct contexts, both extending my dbContext.

public abstract class ParcelLogisticsContext : DbContext
{
	public DbSet<Parcel> Parcel { get; set; }
	public DbSet<HopArrival> HopArrival { get; set; }
	public DbSet<Receipient> Receipient { get; set; }
	public DbSet<Truck> Truck { get; set; }
	public DbSet<Warehouse> Warehouse { get; set; }
	public DbSet<ParcelStorage> ParcelStorage { get; set; }

	public ParcelLogisticsContext(DbContextOptions options) : base(options)
	{

	}
}

public class PgSqlParcelLogisticsContext : ParcelLogisticsContext
{
	public PgSqlParcelLogisticsContext(DbContextOptions options) : base(options)
	{
	}
}

public class SqlServerParcelLogisticsContext : ParcelLogisticsContext
{
	public SqlServerParcelLogisticsContext(DbContextOptions options) : base(options)
	{
	}
}

From now on I added migrations using Add-Migration -Context PgSqlParcelLogisticsContext ChangedAwesomeFields and Add-Migration -Context SqlServerParcelLogisticsContext ChangedAwesomeFields resulting in different Migrations with vendor specific code in them.

The problem i was facing was with dependency injection. When adding EF like below I was unable to use my abstract base class for dependency injection.

switch (Configuration.GetValue<string>("UsedDatabase"))
{
	case "Sql":
		services.AddDbContext<SqlServerParcelLogisticsContext>(options => options.UseSqlServer(Configuration.GetConnectionString("ParcelLogisticsContext")));
	case "NpgSql":
		services.AddEntityFrameworkNpgsql();
		services.AddDbContext<PgSqlParcelLogisticsContext>(options => options.UseNpgsql(Configuration.GetConnectionString("ParcelLogisticsContext")));
		break;
	default:
		throw new Exception("InvalidUsedDatabase");
}

Now exceptions are thrown when trying to get a context like so because Dependency Injection could not find a service for type ParcelLogisticsDbContext:

class Test
{
	public Test(ParcelLogisticsDbContext context)
	{
	}
}

To resolve this issue I added extension methods so I would be able to use AddDbContext with two type arguments in a similar way e.g. AddScoped works and I could use it like this:

switch (Configuration.GetValue<string>("UsedDatabase"))
{
	case "Sql":
		services.AddDbContext<ParcelLogisticsContext, SqlServerParcelLogisticsContext>(options => options.UseSqlServer(Configuration.GetConnectionString("ParcelLogisticsContext")));
		break;
	case "NpgSql":
		services.AddEntityFrameworkNpgsql();
		services.AddDbContext<ParcelLogisticsContext, PgSqlParcelLogisticsContext>(options => options.UseNpgsql(Configuration.GetConnectionString("ParcelLogisticsContext")));
		break;
	default:
		throw new Exception("InvalidUsedDatabase");
}

Do you think this is a good solution or do you have any other ideas? I also submitted a Pull Request (#10454) and I am happy for feedback!

Further technical details

EF Core version: 2.0
Database Provider: Microsoft.EntityFrameworkCore.SqlServer, Npgsql.EntityFrameworkCore.PostgreSQL
Operating system: Windows 10 Version 1703
IDE: Visual Studio 2017 15.4.5

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions