ExecuteScalar在SELECT语句执行后是否立即返回?

5

最近我注意到了一些有趣的行为。

使用SqlCommand.ExecuteScalar()运行MS SQL存储过程时,我的应用程序似乎完全不知道在SELECT完成后出现的任何SQL错误或PRINTs。

最有可能的解释是,在任何SELECT结果出现后,流程控制立即交给C#,而不等待存储过程完成(虽然存储过程在此期间继续默默地执行)。

明显的优点是性能提升(无需等待,因为结果已知),不幸的是,C#应用程序对在该点之后可能发生的任何SQL异常都不知情。

有人可以确认我的解释吗? 是否可以更改此行为?


1
这可能会回答你的问题:https://dev59.com/oWw05IYBdhLWcg3wy012,这也可能有所帮助:http://support.microsoft.com/kb/321903/en-us。 - Tim Schmelter
如果您在流的末尾之前没有读取结果,那么使用DataReaders会发生这种情况。不确定ExecuteScalar是否适用。 - Martin Smith
1个回答

2
ExecuteNonQuery 方法将调用“ExecuteReader”,并立即在返回的 reader 对象上调用“Close”。ExecuteScalar 将调用“Read”一次,选择第一个值(索引 0),然后调用“Close”。
由于 DataReader 本质上只是一个专门的网络流,任何在其当前位置之后返回的信息(当调用 Close 时)都将永远不会到达实际客户端组件,即使服务器可能已经发送了它。这样实现是为了避免在不需要时返回大量数据。
在您的情况下,我看到解决此问题的两个解决方案。
  1. make sure that you use ExecuteReader instead, and read all the way through the result:

    using(var reader = command.ExecuteReader())
    {
        do 
        {
              while (reader.Read()) { /* whatever */ };
        } while (reader.NextResult());
    }
    
  2. If you can control the server side, it will help to move the actual "send-to-client" select to the end of the procedure or batch in question. Like this:

    create proc Demo
    as
    declare @result int
    select top 1 @result = Id from MyTable where Name = 'testing'
    print 'selected result...'
    select @result Id  -- will send a column called "Id" with the previous value
    go
    

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接