I’m having a strange concurrency issue with some code I wrote. First thing you will ask is why am I using CF and using DbModelBuilder… well I have situation where I could have Nth number of databases that will all be identical and I must maintain seperation of data. I’m using CF to prevent a massive model generation issues with multiple devs foobaring my models with their GUI’s. Alas, this is the basic code for what I’m doing.
The two console writelines should never be hit and yet they are.
Can you please try this and let me know where the issue is?
This is the Test Harness console app:
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 100; i++)
{
var workerObject = new Worker();
var workerThread = new Thread(workerObject.DoWork);
workerThread.Start();
}
}
}
public class Worker
{
public void DoWork()
{
var connections = new List<KeyValuePair<string, DynamicDb>>
{
new KeyValuePair<string, DynamicDb>("db1", new MyDynamicEntityLayer("db1").DynamicDb()),
new KeyValuePair<string, DynamicDb>("db2", new MyDynamicEntityLayer("db2").DynamicDb())
};
foreach (var db in connections)
{
if (db.Key == "db1" && db.Value.ConnectionString.Contains("db2"))
Console.WriteLine("THIS SHOULD NEVER HAPPEN!!! db1 : " + db.Value.ConnectionString);
if (db.Key == "db2" && db.Value.ConnectionString.Contains("db1"))
Console.WriteLine("THIS SHOULD NEVER HAPPEN!!! db2 : " + db.Value.ConnectionString);
}
}
}
Here is the entity class:
public class MyDynamicEntityLayer
{
public static string ConnectionString { get; set; }
public MyDynamicEntityLayer(string db = null)
{
MakeAConnectionString(db);
Database.SetInitializer<DynamicDb>(null);
}
public void MakeAConnectionString(string db)
{
var sqlBuilder = new SqlConnectionStringBuilder();
if (db == "db1")
{
sqlBuilder.DataSource = "MySqlServer";
sqlBuilder.InitialCatalog = "db1";
sqlBuilder.ConnectTimeout = 180;
sqlBuilder.IntegratedSecurity = true;
}
else
{
sqlBuilder.DataSource = "MySqlServer";
sqlBuilder.InitialCatalog = "db2";
sqlBuilder.ConnectTimeout = 180;
sqlBuilder.IntegratedSecurity = true;
}
ConnectionString = sqlBuilder.ToString();
}
public DynamicDb DynamicDb()
{
var builder = new DbModelBuilder(DbModelBuilderVersion.Latest);
TableMappingToBuilder(builder);
var compiled = builder.Build(Database.DefaultConnectionFactory.CreateConnection(ConnectionString)).Compile();
return new DynamicDb(compiled);
}
public void TableMappingToBuilder(DbModelBuilder builder)
{
builder.Configurations.Add(new EntityTypeConfiguration<ConcurrencyTest>());
builder.Entity<ConcurrencyTest>().ToTable("ConcurrencyTest", "dbo");
}
}
and my DbContext CS file:
public class DynamicDb : DbContext
{
public string ConnectionString { get; set; }
public DynamicDb(DbCompiledModel model)
: base(MyDynamicEntityLayer.ConnectionString, model)
{
ConnectionString = MyDynamicEntityLayer.ConnectionString;
((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 100;
}
public DbSet<ConcurrencyTest> ConcurrencyTests { get; set; }
}
public class ConcurrencyTest
{
public int ID { get; set; }
public string MyColumn { get; set; }
}
Your issue is:
All worker threads share single value stored in this property and fights for its modification.