简体   繁体   中英

Calling stored procedure from Entity Framework 6 abnormal behavior

I have a stored procedure that takes some time to execute (~60 seconds) that I call using EF like this:

context.Database.ExecuteSqlCommand(
    "myStoredProcedure @param1",
    new SqlParameter("param1", param1)
);

The stored procedure consists of two parts:

  1. inserting a new row into table tblSomeTable and afterwards

  2. calculating some info from multiple tables that do not include tblSomeTable .

The second operation is the time consuming one. When I execute this stored procedure from SSMS I can see that a new row is added to tblSomeTable before the procedure finishes executing which is a normal behavior, but, when I run the same exact procedure using the above code then a new row in tblSomeTable is added only when the procedure finishes executing.

Also while the procedure is running, I cannot query tblSomeTable at all (both from EF and SSMS), from what I assume that there is a lock placed on tblSomeTable until the procedure finishes. Why is this happening?

This is on SQL Server 2008.

According to the documentation :

Starting with EF6 Database.ExecuteSqlCommand() by default will wrap the command in a transaction if one was not already present

So you won't see any changes in SSMS until it ends.

Why is this happening?

It is not an abnormal behavior. You can't see the data inserted into tblSomeTable because when you call context.Database.ExecuteSqlCommand a new SQL Server transaction is created. This is what the documentation says:

If there isn't an existing local or ambient transaction a new transaction will be used to execute the command.

And the default isolation level used for the transaction by EF is the highest which is Serializable . It means that any SQL query that is executed outside of the transaction can't see any data that is currently inserted into tblSomeTable when the transaction is not committed. The data is invisible to your query executed in SSMS when your context.Database.ExecuteSqlCommand doesn't finish its work.

You can change the isolation level but I don't recommend it if the only purpose of that is to check what your stored procedure is doing when calling context.Database.ExecuteSqlCommand .

Edit after @David Browne - Microsoft comment:

The default isolation level of EF is READ COMMITTED and not SERIALIZABLE as I said above. The inability to read data that is not committed is still apply.

Definition from documentation :

Specifies that statements cannot read data that has been modified but not committed by other transactions. This prevents dirty reads. Data can be changed by other transactions between individual statements within the current transaction, resulting in nonrepeatable reads or phantom data. This option is the SQL Server default.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM