Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow a second type argument AddDbContext to support inheritance #10451

Closed
Flexba opened this issue Nov 30, 2017 · 1 comment
Closed

Allow a second type argument AddDbContext to support inheritance #10451

Flexba opened this issue Nov 30, 2017 · 1 comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-enhancement
Milestone

Comments

@Flexba
Copy link
Contributor

Flexba commented Nov 30, 2017

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

@ajcvickers
Copy link
Member

@Felixhacks It doesn't look to me like this needs any change in EF. To resolve the context as some type other than what it is registered as, just add the service to D.I. in the normal way. For example:

services.AddDbContext<SqlServerParcelLogisticsContext>(
    options => options.UseSqlServer(Configuration.GetConnectionString("ParcelLogisticsContext")));

services.AddScoped<ParcelLogisticsContext>(
    p => p.GetService<SqlServerParcelLogisticsContext>())

Also, I'm curious as to why you have a call to AddEntityFrameworkNpgsql? This should not be required except in unusual circumstances. What happens if you remove this call?

@ajcvickers ajcvickers added this to the 2.1.0 milestone Feb 5, 2018
@ajcvickers ajcvickers added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Feb 5, 2018
@ajcvickers ajcvickers modified the milestones: 2.1.0-preview2, 2.1.0 Nov 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-enhancement
Projects
None yet
Development

No branches or pull requests

2 participants