I have a transaction that is going to be executed concurrently, when there exists an entry for the given reference, I have to update the data, otherwise I have to create a record an set the reference accordingly. So far, the code I have goes like this:
using (var context = new MyDbContext())
{
using (var scope = context.Database.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
{
try
{
MyModel model = null;
int hasEntry = context.MyModel.Where(x => x.refID == refID).Count();
if (hasEntry == 0)
{
model = new MyModel();
model.refID = refID;
}
else
{
model = context.MyModel.Where(x => x.refID == refID).Single();
}
// process model object...
if (hasEntry == 0)
{
context.MyModel.Add(model);
}
else
{
context.Entry(model).State = EntityState.Modified;
}
context.SaveChanges();
scope.Commit();
}
catch(Exception)
{
scope.Rollback();
}
}
}
When two (or more) instances run the first one inserts but then remaning ones do not update. They throw an DBUpdateException complaining about a PK being violated.
I don't know why the ones that have to update are actually trying to insert. They get an ID that was already added to the table so they throw the exception.
AFAIK the IsolationLevel.ReadCommitted should lock the rows and just free them when the transaction is done. According to the documentation (https://msdn.microsoft.com/en-us/library/cc546518.aspx) "If your connection is using the read committed isolation level and SQL Server encounters a dirty row while executing a DML statement, it will wait until the transaction that currently owns the row has been committed or rolled back before continuing execution."
So, I guess I am having a dirty read because the instances are not waiting for the instance that inserts in the first place, so they try to insert (with an already used id) and there comes the PK violation.
What am I missing?
PD: This is my first project using c# and entityframework. I have searched a lot and have not found any answer, excuse me if the question is kind of silly.