C#控制台程序导入API XML数据至SQL Server失败,求解决
问题分析与解决方案
核心错误点
- 空引用异常:代码中
Person person = null;从未被赋值,直接使用person.ID等属性会抛出空引用异常,导致插入逻辑根本无法执行。 - 未遍历API返回的数组:API返回的是
Person[]数组,代码没有循环遍历数组中的每个对象,只尝试插入一条(还是null的)数据。 - 连接释放重复操作:外层
using (SqlConnection con)已经会自动管理连接的打开和关闭,嵌套的using (con)和手动con.Close()属于冗余操作,可能导致连接提前释放。 - 无异常捕获:执行过程中出现错误时没有任何提示,无法定位问题。
- 单条插入性能低下:1万条数据单条插入会大幅消耗数据库资源,效率极低。
- XML反序列化潜在问题:
ReadAsAsync<Person[]>默认依赖JSON格式化器,若API返回纯XML,可能无法正确反序列化为Person数组。
修正后的代码(直接批量入库版本)
控制台程序代码
using System; using System.Configuration; using System.Data.SqlClient; using System.Net.Http; using System.Net.Http.Formatting; using System.Threading.Tasks; class Program { static void Main(string[] args) { try { var importTask = ImportApiDataToSql(); importTask.Wait(); Console.WriteLine("数据导入完成"); } catch (Exception ex) { Console.WriteLine($"导入失败:{ex.Message}"); Console.WriteLine($"详细错误:{ex.InnerException?.Message}"); } Console.ReadKey(); } static async Task ImportApiDataToSql() { using (HttpClient client = new HttpClient()) { Console.WriteLine("调用API中..."); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml")); var response = await client.GetAsync("http://localhost/webapi/api/user"); response.EnsureSuccessStatusCode(); // 反序列化XML到Person数组(显式指定XML格式化器) var persons = await response.Content.ReadAsAsync<Person[]>(new[] { new XmlMediaTypeFormatter() }); Console.WriteLine($"API返回 {persons.Length} 条记录"); // 使用SqlBulkCopy批量插入,提升大数量数据处理性能 using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnection"].ConnectionString)) { await con.OpenAsync(); using (SqlBulkCopy bulkCopy = new SqlBulkCopy(con)) { bulkCopy.DestinationTableName = "tblPerson"; // 映射实体属性与数据库列名 bulkCopy.ColumnMappings.Add("ID", "ID"); bulkCopy.ColumnMappings.Add("Name", "Name"); bulkCopy.ColumnMappings.Add("Mobile", "Mobile"); bulkCopy.ColumnMappings.Add("Birthday", "Birthday"); await bulkCopy.WriteToServerAsync(persons.ToDataTable()); } } } } } // 辅助方法:将泛型集合转换为DataTable,适配SqlBulkCopy public static class CollectionExtensions { public static System.Data.DataTable ToDataTable<T>(this System.Collections.Generic.IEnumerable<T> items) { var dataTable = new System.Data.DataTable(typeof(T).Name); var properties = typeof(T).GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); foreach (var prop in properties) { dataTable.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType); } foreach (var item in items) { var values = new object[properties.Length]; for (int i = 0; i < properties.Length; i++) { values[i] = properties[i].GetValue(item) ?? DBNull.Value; } dataTable.Rows.Add(values); } return dataTable; } }
实体类代码(保持不变)
public class Person { public int ID { get; set; } public string Name { get; set; } public string Mobile { get; set; } public DateTime Birthday { get; set; } }
存储为XML字符串入库的替代方案
如果需要将API返回的XML直接存储为字符串,可修改API数据获取与插入逻辑:
// 获取原始XML字符串 string xmlContent = await response.Content.ReadAsStringAsync(); // 插入到数据库(假设表存在XmlContent列,类型为nvarchar(max)或xml) using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnection"].ConnectionString)) { await con.OpenAsync(); string sql = "INSERT INTO tblPersonXml (XmlContent) VALUES (@xmlContent)"; using (SqlCommand cmd = new SqlCommand(sql, con)) { cmd.Parameters.AddWithValue("@xmlContent", xmlContent); await cmd.ExecuteNonQueryAsync(); } }
关键优化说明
- 异步编程改进:使用
async/await替代Wait(),避免线程阻塞,提升程序响应性。 - 批量插入:使用
SqlBulkCopy处理大量数据,比单条插入效率提升数十倍。 - 异常捕获:添加全局异常捕获,输出错误信息方便排查问题。
- XML反序列化修正:显式指定
XmlMediaTypeFormatter,确保XML数据能正确反序列化为实体数组。 - 连接管理:通过
using语句自动管理数据库连接,避免连接泄漏。
内容的提问来源于stack exchange,提问作者user19928919
相关产品推荐
相关产品推荐

