如何在SqlDataReader打开状态下执行SQL查询?
解决SqlDataReader打开时执行SQL查询的问题
首先,你遇到的System.InvalidOperationException错误,核心原因是SQL Server默认不允许在同一个数据库连接上同时运行一个打开的DataReader和另一个SQL命令。下面给你几种可行的解决方案,以及解答你的其他疑问:
方案1:启用MultipleActiveResultSets (MARS)
这是最简单的解决方式,只需要修改你的连接字符串,添加MultipleActiveResultSets=True配置,这样同一个连接就可以同时处理DataReader和其他SQL命令了。
修改后的连接字符串示例:
var builder = new SqlConnectionStringBuilder(); builder.ConnectionString = "你的原有连接字符串"; builder.MultipleActiveResultSets = true; // 启用MARS using (SqlConnection connection = new SqlConnection(builder.ConnectionString)) { // 你的原有代码逻辑 }
方案2:先读取所有数据到List,再关闭DataReader执行插入
既然你需要把SqlDataReader返回的值存储到List中,你可以先一次性把所有数据加载到内存的List里,然后关闭DataReader,再执行循环插入操作。这样就不会占用连接,避免冲突:
using (SqlConnection connection = new SqlConnection(builder.ConnectionString)) { connection.Open(); Console.WriteLine("\n List of Bracelets:"); Console.WriteLine("=========================================\n"); List<object> al = new List<object>(); string selectQuery = "你的查询语句"; // 补充你的查询命令 using (SqlCommand command = new SqlCommand(selectQuery, connection)) { // 先读取所有数据到List using (SqlDataReader reader = command.ExecuteReader()) { while (reader.Read()) { Console.WriteLine(String.Format(" Id Bracelet :{0} | Id Client: {1} | First Name: {2} | Last Name: {3}", reader["IdBracelet"], reader["IdClient"], reader["FirstName"], reader["LastName"])); al.Add(reader["IdBracelet"]); } } // reader在这里自动关闭 } // 现在执行循环插入操作 while (true) { Y.Function(); string strQueryInsert = "Insert into TableZ(xxx, xx, xxxx, xxxxx, xxxxxx) values (@xxx, @xx, @xxxx, @xxxxx, @xxxxxx)"; using (SqlCommand cmd = new SqlCommand(strQueryInsert, connection)) { cmd.Parameters.AddWithValue("@xxx", xxx); cmd.Parameters.AddWithValue("@xx", xx); cmd.Parameters.AddWithValue("@xxxx", xxxx); cmd.Parameters.AddWithValue("@xxxxx", xxxxx); cmd.Parameters.AddWithValue("@xxxxxx", xxxxxx); cmd.ExecuteNonQuery(); } Thread.Sleep(5000); } }
方案3:使用独立的第二个数据库连接
如果不想启用MARS,也不想提前加载所有数据,你可以在插入操作中新建一个独立的SqlConnection,这样两个连接互不干扰:
using (SqlConnection connection = new SqlConnection(builder.ConnectionString)) { connection.Open(); Console.WriteLine("\n List of Bracelets:"); Console.WriteLine("=========================================\n"); List<object> al = new List<object>(); string selectQuery = "你的查询语句"; using (SqlCommand command = new SqlCommand(selectQuery, connection)) { using (SqlDataReader reader = command.ExecuteReader()) { while (reader.Read()) { Console.WriteLine(String.Format(" Id Bracelet :{0} | Id Client: {1} | First Name: {2} | Last Name: {3}", reader["IdBracelet"], reader["IdClient"], reader["FirstName"], reader["LastName"])); al.Add(reader["IdBracelet"]); // 这里使用新的连接执行插入 using (SqlConnection insertConn = new SqlConnection(builder.ConnectionString)) { insertConn.Open(); Y.Function(); string strQueryInsert = "Insert into TableZ(xxx, xx, xxxx, xxxxx, xxxxxx) values (@xxx, @xx, @xxxx, @xxxxx, @xxxxxx)"; using (SqlCommand cmd = new SqlCommand(strQueryInsert, insertConn)) { cmd.Parameters.AddWithValue("@xxx", xxx); cmd.Parameters.AddWithValue("@xx", xx); cmd.Parameters.AddWithValue("@xxxx", xxxx); cmd.Parameters.AddWithValue("@xxxxx", xxxxx); cmd.Parameters.AddWithValue("@xxxxxx", xxxxxx); cmd.ExecuteNonQuery(); } } Thread.Sleep(5000); } } } }
你的其他疑问解答
1. 插入语法是否正确?
你的插入语法是正确的,使用参数化查询的方式可以有效避免SQL注入,只要确保:
- 参数名
@xxx等和SQL语句中的占位符完全对应 - 参数值的类型和
TableZ表中对应字段的数据类型匹配
2. 是否需要打开第二个连接?
这取决于你选择的解决方案:
- 如果启用了MARS,不需要第二个连接,同一个连接可以同时处理DataReader和插入命令
- 如果选择提前加载数据到List,也不需要第二个连接,关闭DataReader后复用原连接即可
- 如果要在DataReader打开的同时执行插入,又不想启用MARS,就需要第二个独立的连接
内容的提问来源于stack exchange,提问作者Valentin Kohler
相关产品推荐
相关产品推荐

