0

When I execute a SQL query using Entity Framework that creates a transaction and locks a certain table to perform a time consuming operations on it, what happens when another application tries to read from the same table at the same time?

Will SQL Server wait for the first transaction to finish and proceed when the lock is gone or will it simply return with an error saying that the table is inaccessible?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
astralmaster
  • 2,344
  • 11
  • 50
  • 84
  • 1
    If you want a wait-in-line sorta thing, you are looking for the `serializable` isolation level. [SQL Server Isolation Levels: A Series - Paul White](https://sqlperformance.com/2014/07/t-sql-queries/isolation-levels). Note this does not necessarily lock the whole table, depending on the operation and indexes available the engine will try to use a key-range lock. [Key-Range Locking - MSDN](https://technet.microsoft.com/en-us/library/ms191272(v=sql.105).aspx) – SqlZim Sep 15 '17 at 19:07
  • 1
    **By default**, SQL Server does **row-level locking**, so you hardly ever lock an entire table. If you insert new rows - yes, those new rows cannot be read by another transaction until the transaction the rows are being inserted in is **committed** - but that doesn't mean the entire table has to be locked just to allow insert (or update or delete) of a few rows! – marc_s Sep 15 '17 at 20:08

3 Answers3

2

By default EF will create SQL Server databases with READ COMMITTED SNAPSHOT on. This means that writers don't block readers and readers don't block writers. For details on Row-Version-based Isolation Levels see Snapshot Isolation in SQL Server.

While SaveChanges() has rows locked in a transactions, other sessions attempting to read those rows will be redirected to the version store, and read the last-known-good version of those rows. In other words readers see each table at a consistent point-in-time just before any in-flight transactions.

If you use EF against an existing database, it might not be configured with READ COMMITTED SNAPSHOT, and in that case readers attempting to read a row locked by a transaction will block until the end of the transaction. Normally this is only a few milliseconds, unless there are a large number of transactions running and the reader is trying to scan a lot of rows, or there are longer-running transaction. In that case you should work to move the database to READ COMMITTED SNAPSHOT in the future.

David Browne - Microsoft
  • 80,331
  • 6
  • 39
  • 67
1

Yes, Entity Framework is creating a transaction automatically when SaveChanges is called and the default isolation level is Read Committed (actually it is fetched from the provider and SQL Server's default is Read Committed).

More details can be found within this documentation page.

In order to change isolation level, you can inhibit EF's context to use it's own transaction (contextOwnsConnection: false) when instantiating the context.

My preferred alternative is to use TransactionScope as it does not require to make any changes to the way you instantiate the context, save the changes etc. However, beware that its default isolation level is Serializable (referenced question and answer also show you how to change it)

NOTE: having long transactions is not recommended, maybe you should take a look upon using bulk operations (or check this library) to avoid multiple inserts/updates/deleted generated by normal changes save.

Alexei - check Codidact
  • 22,016
  • 16
  • 145
  • 164
-1

The answer is, it depends. There are any of a number of ways SQL can lock data. Generally speaking, if you have a DML operation (Insert, Update, Delete) going on, and you attempt to select from that table, it will block the select until the DML operation completes.

That can be overridden (at your own peril) by either using with (nolock) or set transaction isolation level read uncommmitted. Doing one of those basically allows your query to read "whatever the data currently looks like" which could be incomplete, or even contain rows which, by the time the transaction would have completed, won't exist.

The only time it would return an error is if your actual connection timed out (which would be something in your applications connection settings) or if you caused a deadlock on the table (a much more complicated subject).

Xedni
  • 3,662
  • 2
  • 16
  • 27