-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Description
When using the same DbContext class (e.g. DbContext itself) with different connection strings, the Connection Resiliency Feature of .Net 4.5 causes DB-creation and deletion (EnsureCreated/EnsureDeleted) to take a long time (due to the DB-Existency checks).
I made a small repro sample where you can see the different effects.
Basically when using 2 default connection strings (without modified connection resiliency settings) with the same DbContext class, the DB-Creation takes >10s (as this seems to be the default ConnectRetryInterval, even when the MSDN docs suggest something else).
Repro sample
static void Main (string[] args)
{
// Default resiliency settings (since .NET 4.5)
var defaultConnectionString = "Data Source=localhost;Initial Catalog=EFIdleResiliencyBug1;Integrated Security=SSPI";
// Retry Interval = 3s (instead of 10 which seems to be the default)
var connectionStringThreeSeconds = "Data Source=localhost;Initial Catalog=EFIdleResiliencyBug2;Integrated Security=SSPI;ConnectRetryInterval=3";
// Retry Count = 0 (instead of 1) => means Resiliency Feature is disabled.
var connectionStringZeroRetry = "Data Source=localhost;Initial Catalog=EFIdleResiliencyBug3;Integrated Security=SSPI;ConnectRetryCount=0;";
// Here we also create a default connection string but with a different db
var defaultConnectionString2 = "Data Source=localhost;Initial Catalog=EFIdleResiliencyBug4;Integrated Security=SSPI";
Drop(defaultConnectionString); // takes > 10s
Drop(connectionStringZeroRetry); // Takes no time (connection resiliency disabled)
Drop(connectionStringThreeSeconds); // takes > 3s
Drop(defaultConnectionString2); // takes > 10s
//All connection strings (same DbContext class) try to connect to the DB.
Create(defaultConnectionString); // BUG: Takes 10s
Create(connectionStringThreeSeconds); // BUG: Takes 3s
Create(connectionStringZeroRetry); // Takes no time (connection resiliency disabled)
Create(defaultConnectionString2); // BUG: Takes 10s (seems to be the default RetryInterval for some reason).
// Note: When using a different derived class from DBContext for each connection string the bug does not exist.
// Expected Behavior: Ignore connection resiliency for checking if the db exists. (It should not take 3s or even 10s).
// This is especially a problem when executing integration / unit tests that drop the db at the beginning.
}
private static void Create(string connectionString)
{
Console.WriteLine($"Creating {connectionString}");
var sw = Stopwatch.StartNew();
using (var dbContext = new TestDbContext(connectionString))
{
dbContext.Database.EnsureCreated();
Console.WriteLine("Creating DB took: " + sw.Elapsed);
}
}
private static void Drop(string connectionString)
{
Console.WriteLine($"Droping {connectionString}");
var sw = Stopwatch.StartNew();
using (var dbContext = new TestDbContext(connectionString))
{
sw = Stopwatch.StartNew();
dbContext.Database.EnsureDeleted();
Console.WriteLine("Deleting DB took: " + sw.Elapsed);
}
}
public class TestDbContext : DbContext
{
private readonly string _connectionString;
public TestDbContext(string connectionString)
{
_connectionString=connectionString;
}
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
options.UseSqlServer(_connectionString);
}
}
I hope this helps you fix the API or adapt the docs.
But in my opinion the current API (EF Core) suggests that you can use the same class (DBContext) for multiple connection strings (ctor for this). However with .Net 4.5 that causes serious performance problems.
This is especially noticable in our unit / integration tests where we drop multiple DBs with the same DBContext class and recreate them later.
Note: This issue was ported from EF 6 (http://entityframework.codeplex.com/workitem/2899) and re-tested with the EF.Core 1.1.0 (nuget package)