简体   繁体   English

从Entity Framework 6异常行为中调用存储过程

[英]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: 我有一个存储过程需要花费一些时间(〜60秒)才能执行,我使用EF这样调用它:

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 在表tblSomeTable插入新行,然后

  2. calculating some info from multiple tables that do not include tblSomeTable . 从不包含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. 当我从SSMS执行此存储过程时,我可以看到在过程完成执行之前将新行添加到tblSomeTable 这是正常现象,但是,当我使用上述代码运行相同的确切过程时,则tblSomeTable的新行是仅在过程完成执行时添加。

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. 另外,在过程运行时,我无法从tblSomeTable上查询到tblSomeTable (都来自EF和SSMS),因为我假设tblSomeTabletblSomeTable放置了锁,直到过程完成为止。 Why is this happening? 为什么会这样呢?

This is on SQL Server 2008. 这是在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 默认情况下,从EF6 Database.ExecuteSqlCommand()开始,会将命令包装在事务中(如果尚不存在)

So you won't see any changes in SSMS until it ends. 因此,直到SSMS结束,您都不会看到任何更改。

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. 您看不到插入到tblSomeTable的数据,因为在调用context.Database.ExecuteSqlCommand时,将创建一个新的SQL Server事务。 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 . EF用于事务的默认隔离级别是最高的,即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. 这意味着在未提交事务时,在事务外部执行的任何SQL查询都看不到当前插入到tblSomeTable任何数据。 The data is invisible to your query executed in SSMS when your context.Database.ExecuteSqlCommand doesn't finish its work. context.Database.ExecuteSqlCommand未完成其工作时,该数据对于在SSMS中执行的查询不可见。

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 . 您可以更改隔离级别,但是如果这样做的唯一目的是在调用context.Database.ExecuteSqlCommand时检查存储过程在做什么,则我不建议您这样做。

Edit after @David Browne - Microsoft comment: @David Browne之后编辑 -微软评论:

The default isolation level of EF is READ COMMITTED and not SERIALIZABLE as I said above. EF的默认隔离级别是READ COMMITTED,而不是如上所述的SERIALIZABLE 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. 此选项是SQL Server的默认选项。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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