为什么无法将MS-SQL数据库的所有表读取到DataSet中
报错含义
你遇到的报错是SQL Server ADO.NET提供程序的经典限制:默认状态下,同一个数据库连接同一时间只能有一个处于活动状态的DataReader。你当前外层通过ExecuteReader()打开了读取表名的SqlDataReader,在该Reader未关闭、仍在逐行读取的过程中,又用同一个连接让SqlDataAdapter发起了查询表数据的新请求,两个操作争夺同一个连接的使用权,就触发了该错误。
该报错和SqlDataAdapter无关,它本身没有Close()方法,Fill操作执行完成后会自动释放内部关联的命令资源,不需要手动关闭。
解决方案
方案1(优先推荐):先读取全量表名再拉取单表数据
先把所有表名读取到本地的List中存储,关闭占用连接的DataReader后,再循环遍历表名列表拉取每个表的内容,从根源上避免连接占用冲突。
修改后的代码示例:
try { DbConnection.Open(); List<string> tableNames = new List<string>(); // 第一步:先读取所有表名存到本地,读完立即关闭DataReader using (var sqlCommand = DbConnection.CreateCommand()) { sqlCommand.CommandText = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES"; using (var sqlDataReader = sqlCommand.ExecuteReader()) { while (sqlDataReader.Read()) { tableNames.Add(sqlDataReader.GetString(0)); } } } // 第二步:循环拉取每个表的数据,此时无其他DataReader占用连接 cmb_Table_Names.Items.Clear(); dataSet.Tables.Clear(); foreach (var tableName in tableNames) { cmb_Table_Names.Items.Add(tableName); DataTable dt_tmp = new DataTable(); using (var da = new SqlDataAdapter($"SELECT * FROM {tableName}", DbConnection)) { da.Fill(dt_tmp); } dataSet.Tables.Add(dt_tmp); } } catch (Exception ex) { MessageBox.Show(ex.Message, "Reading DB failed!!!", MessageBoxButton.OK); }
上述代码额外增加了using语句包裹可释放资源,避免出现资源泄漏问题。
方案2:开启多活动结果集(MARS)
如果业务场景确实需要在同一个连接上同时执行多个查询,可以修改数据库连接字符串,添加配置项MultipleActiveResultSets=True,开启后即可支持同一连接上存在多个活动的查询操作。该方案不需要修改业务逻辑,但会小幅增加连接的资源占用,没有特殊需求时优先选择方案1。
内容的提问来源于stack exchange,提问作者Dominique
相关产品推荐
相关产品推荐

