修改存储过程后DataTable返回空表,DataSet却正常的技术求助
OleDbDataAdapter填充DataTable时存储过程返回空的问题解决思路
先理清楚你的核心问题
你遇到的这个情况挺常见的:
- 原存储过程只执行
SELECT语句时,VB.NET里用OleDbDataAdapter.Fill(DataTable)能正常拿到所有数据 - 改成先写入表变量(或者先执行DELETE/INSERT再查询实体表)后,同样的代码返回0列0行,完全没有报错
- 但换成填充DataSet时,
Fill(DataSet)却能正常获取数据
为什么会出现这种差异?
这是OleDb与SQL Server存储过程交互的特性导致的:
当存储过程中包含DML操作(INSERT/DELETE/UPDATE)或者通过表变量写入后查询时,SQL Server会先返回DML操作的影响行数作为第一个结果集,而你真正需要的查询结果是第二个结果集。
Fill(DataTable)默认只会读取第一个结果集,这个结果集仅包含行数统计信息,没有实际的列和行数据,所以你的DataTable会是空的- 而
Fill(DataSet)会自动遍历所有返回的结果集,把第二个有效查询结果集加载到DataSet的DataTable中,因此能正常拿到数据
解决办法(按优先级排序)
1. 在存储过程开头添加SET NOCOUNT ON(最推荐)
这是最简单直接的方案,它会让SQL Server不返回DML操作的影响行数结果集,只返回你需要的查询数据:
CREATE PROCEDURE YourProcedureName AS BEGIN SET NOCOUNT ON; -- 关键语句 DECLARE @Table TABLE (Column1 <对应类型> PRIMARY KEY NOT NULL, Column2 <对应类型> NOT NULL) INSERT INTO @Table (Column1, Column2) SELECT <修改后的查询语句> SELECT [TAB].[Column1], [TAB].[Column2] FROM @Table [TAB] END
添加后,你可以在SSMS里执行存储过程,查看「消息」面板——原来会显示的(X 行受影响)提示会消失,对应OleDb只会收到一个有效查询结果集,Fill(DataTable)就能正常加载数据了。
2. 在VB.NET代码中手动跳过第一个结果集(无法修改存储时使用)
如果不能调整存储过程,可以在代码里强制读取第二个结果集:
' 原填充DataTable的代码执行后,补充以下逻辑 oAdapter.Fill(dataTable) ' 跳转到下一个结果集 Dim reader = oAdapter.SelectCommand.ExecuteReader() reader.NextResult() ' 重新填充DataTable oAdapter.Fill(dataTable)
不过这个方法有局限性,如果存储过程的结果集数量发生变化,代码可能会出现异常,所以优先推荐第一种方案。
3. 改用SqlClient替代OleDb(长期优化方案)
如果你的数据库是SQL Server,建议直接使用System.Data.SqlClient(.NET Core/.NET 5+版本使用Microsoft.Data.SqlClient),它对SQL Server的适配性更好,默认会忽略影响行数的结果集,直接读取查询结果。修改代码时只需将所有OleDb开头的类替换为Sql开头的类即可(比如SqlConnection、SqlCommand、SqlDataAdapter)。
内容的提问来源于stack exchange,提问作者user6499401
相关产品推荐
相关产品推荐

