Question

Here is the code:

using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
    DBContext.AddtoSomeTable(record);
    System.Threading.Thread.Sleep(5000);
    DBContext.SaveChanges();

    MAX_ID = (from t in DBContext.SomeTable
              select t.ID).Max();

    scope.Complete();
}

As far as I know, before the scope is completed, the MAX_ID should be the new record's ID, which is just inserted. Even if there are two users submitting at the same time, the later one should wait until the first one's TransactionScope is completed.

But, what happens is the two users get the same MAX_ID. That means after the first person's record is inserted into the database, then the second one's record is inserted, and then the first person gets his MAX_ID.

I thought during a transaction the table was locked to avoid dirty data. Can anyone explain this?

Edit: the ID field is auto incremented

Was it helpful?

Solution

Locks of different types and scopes are taken during an operation and the lock scope will change due to lock escalation as the number of locks increases. If, in a single transaction, you are inserting/update/delete a single row in a single table, an exclusive row lock will most likely be taken. As you update/insert/delete more rows in that table, once you accumulate a certain number of row locks, lock escalation will promote them to page locks. Accumulate a sufficiency of page locks and you'll upgrade to a table lock.

I don't know what you're trying to do with select max(id) from someTable, but if you expect it to reflect what your SaveChanges() operation just did, most likely, you're creating a race condition.

Assuming you're using SQL Server, the built-in function scope_identity() will give you

the last identity value inserted into an identity column in the same scope. A scope is a module: a stored procedure, trigger, function, or batch."

However: if, in the same scope, you, say, insert a row into two different tables, each having an identity column,

begin transaction
insert foo () ...
insert bar () ...
commit transaction

scope_identity() gives you just the last value that your scope generated (for the table bar in this example).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top