C#中SqlCommand在foreach循环同一迭代内重复执行致数据重复
解决输出表重复行的问题
看起来你遇到的重复行问题,大概率是因为**APIAddress这个静态类的全局属性没有在每次循环后重置**。你直接用类名访问APIAddress.FORMATTED_ADDRESS、APIAddress.ADDRESS_ID这些属性,如果APIAddress是静态类,这些属性会在整个应用域里共享状态——要是某次API调用没更新这些属性(比如调用失败、返回空),下一次循环就会用上一次的有效数据,自然就插入了重复行。
下面是具体的修复步骤和优化后的代码:
1. 重构API调用逻辑,避免静态全局状态
不要再用静态类的属性存储API响应,改成让CallGoogleAPI方法返回一个包含响应数据的实体对象。这样每次调用都能拿到当前行对应的独立结果,不会和其他行的结果串味。
先定义一个存储API响应的实体类:
public class GoogleApiResponse { public int AddressId { get; set; } public string FormattedAddress { get; set; } public string PostalCode { get; set; } }
然后修改CallGoogleAPI方法,让它返回这个实体:
// 假设原方法是静态的,现在调整为返回响应实体 public static GoogleApiResponse CallGoogleAPI(int addressId, string originalAddress) { // 这里写你的API调用逻辑,比如调用Google地图API var response = new GoogleApiResponse(); response.AddressId = addressId; // 模拟API调用后的赋值,替换成你实际的解析逻辑 var apiResult = /* 调用Google API并获取结果 */; if (apiResult != null) { response.FormattedAddress = apiResult.FormattedAddress; response.PostalCode = apiResult.PostalCode; } return response; }
2. 修改循环插入逻辑,使用独立的响应对象
在循环处理每行数据时,直接使用当前API调用返回的实体对象,不再依赖静态属性:
foreach (DataRow record in datatable.Rows) { int addrId = (int)record[0]; string originalAddr = (string)record[1]; // 获取当前行专属的API响应 var apiResponse = APIAddress.CallGoogleAPI(addrId, originalAddr); // 只有当响应有效时才插入 if (apiResponse != null && !string.IsNullOrWhiteSpace(apiResponse.FormattedAddress)) { using (SqlConnection connection = new SqlConnection(sqlconn)) { // 替换成你实际的插入SQL语句 string insertCmd = @"INSERT INTO OutputTable (ADDR_ID, ADDR_ONE, POSTALCODE) VALUES (@ADDR_ID, @ADDR_ONE, @POSTALCODE)"; using (SqlCommand command = new SqlCommand(insertCmd, connection)) { connection.Open(); // 正确传递参数,注意DBNull的使用 command.Parameters.AddWithValue("@ADDR_ID", apiResponse.AddressId); command.Parameters.AddWithValue("@ADDR_ONE", apiResponse.FormattedAddress ?? DBNull.Value); command.Parameters.AddWithValue("@POSTALCODE", apiResponse.PostalCode ?? DBNull.Value); command.ExecuteNonQuery(); // 不需要手动Clear参数,因为每次循环都会新建SqlCommand实例 } } } }
3. 额外的防重复措施
- 检查你的输入查询
varSqlquery,确认它返回的每行都是唯一的(比如record[0]作为主键没有重复)。可以在调试时查看datatable里的数据,确保没有重复行输入。 - 给输出表的
ADDR_ID字段设置主键或唯一索引,这样即使代码还有问题,数据库层面也会拒绝重复插入,避免数据污染。 - 原代码里
DBNull.Value.ToString()是错误的,会把数据库NULL转换成空字符串,直接用DBNull.Value才是正确的方式。
内容的提问来源于stack exchange,提问作者sab
相关产品推荐
相关产品推荐

