Reputation: 2465
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?
Upvotes: 0
Views: 5977
Reputation: 89101
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.
Upvotes: 2
Reputation: 23078
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.
Upvotes: 1
Reputation: 4695
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).
Upvotes: -1