You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#实现JSON响应按条件写入SQL Server数据库的问题求助

问题修正与解决方案

一、核心问题梳理

你的代码存在以下关键问题,导致无法实现需求:

  1. 模型字段映射错误:JSON返回字段(如logtime、lat_value)与模型属性名不匹配,反序列化会失败
  2. 反序列化结果未保留:JsonParser方法中反序列化后未存储结果,后续无法使用数据
  3. 批量操作不适用业务逻辑:SqlBulkCopy仅适合无差别批量插入,无法实现你需要的「带条件插入/更新」逻辑
  4. 缺少条件判断逻辑:未实现UnemploymentRate>70及后续的插入/更新判断
  5. 冗余代码:using块会自动关闭数据库连接,无需手动调用sqlCon.Close()

二、分步修正与实现

1. 修正模型类(添加JSON字段映射)

使用JsonProperty特性将模型属性与JSON字段一一对应,确保反序列化成功:

using Newtonsoft.Json;

public class ModelClass
{
    [JsonProperty("logtime")]
    public string LogTime { get; set; }

    [JsonProperty("lat_value")]
    public string Lat { get; set; }

    [JsonProperty("long_value")]
    public string Long { get; set; }

    [JsonProperty("name")]
    public string Name { get; set; }

    [JsonProperty("population")]
    public string Population { get; set; }

    [JsonProperty("unemployment_rate")]
    public decimal UnemploymentRate { get; set; }
}

2. 保存API获取的数据

修改数据获取方法,将反序列化后的结果存储为类成员变量,供后续数据库操作使用:

using RestSharp;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;

public class ControllerClass
{
    private readonly string _url = "https://my-url-goes-here.net";
    private List<ModelClass> _apiData; // 存储API返回的数据

    public void FetchApiData()
    {
        var client = new RestClient(_url);
        var request = new RestRequest("api/constructorName", Method.Get)
        {
            Timeout = -1
        };
        request.AddHeader("api-key", "myKeyGoesHere");
        request.AddParameter("param1", "someParam");
        
        RestResponse response = client.Execute(request);

        if (!string.IsNullOrEmpty(response.Content))
        {
            _apiData = JsonConvert.DeserializeObject<List<ModelClass>>(response.Content);
        }
    }

3. 实现带条件的插入/更新逻辑

这里提供两种实现方式,推荐使用MERGE语句(高效批量处理):

方式一:使用SQL MERGE语句(推荐)

通过MERGE语句一次性处理所有符合条件的记录,减少数据库交互次数:

using System.Data.SqlClient;
using System.Configuration;

public void SyncDataToDatabase()
{
    if (_apiData == null || !_apiData.Any())
        return;

    // 过滤出失业率>70的记录
    var filteredData = _apiData.Where(d => d.UnemploymentRate > 70).ToList();
    if (!filteredData.Any())
        return;

    using (SqlConnection sqlCon = new SqlConnection(ConfigurationManager.ConnectionStrings["Conn"].ConnectionString))
    {
        sqlCon.Open();

        // 创建临时表存储待处理数据
        using (var createTempTableCmd = new SqlCommand(@"
            CREATE TABLE #TempData (
                LogTime VARCHAR(50),
                Lat VARCHAR(50),
                Long VARCHAR(50),
                Name VARCHAR(100),
                Population VARCHAR(50),
                UnemploymentRate DECIMAL(18,2)
            )", sqlCon))
        {
            createTempTableCmd.ExecuteNonQuery();
        }

        // 将过滤后的数据批量插入临时表
        using (SqlBulkCopy bulkCopy = new SqlBulkCopy(sqlCon))
        {
            bulkCopy.DestinationTableName = "#TempData";
            bulkCopy.ColumnMappings.Add("LogTime", "LogTime");
            bulkCopy.ColumnMappings.Add("Lat", "Lat");
            bulkCopy.ColumnMappings.Add("Long", "Long");
            bulkCopy.ColumnMappings.Add("Name", "Name");
            bulkCopy.ColumnMappings.Add("Population", "Population");
            bulkCopy.ColumnMappings.Add("UnemploymentRate", "UnemploymentRate");
            bulkCopy.WriteToServer(filteredData.AsDataReader());
        }

        // 使用MERGE执行插入/更新逻辑
        using (var mergeCmd = new SqlCommand(@"
            MERGE INTO tbl_name AS Target
            USING #TempData AS Source
                ON Target.Name = Source.Name
            WHEN MATCHED AND Target.Unemployment != Source.UnemploymentRate THEN
                UPDATE SET 
                    Target.logtime = Source.LogTime,
                    Target.Latitude = Source.Lat,
                    Target.Longitude = Source.Long,
                    Target.Population = Source.Population,
                    Target.Unemployment = Source.UnemploymentRate
            WHEN NOT MATCHED THEN
                INSERT (logtime, Latitude, Longitude, Name, Population, Unemployment)
                VALUES (Source.LogTime, Source.Lat, Source.Long, Source.Name, Source.Population, Source.UnemploymentRate);
            DROP TABLE #TempData;", sqlCon))
        {
            mergeCmd.ExecuteNonQuery();
        }
    }
}
方式二:逐行查询判断(适合数据量小的场景)

如果数据量不大,可以逐行查询数据库现有记录,再执行插入或更新:

public void SyncDataToDatabase()
{
    if (_apiData == null || !_apiData.Any())
        return;

    using (SqlConnection sqlCon = new SqlConnection(ConfigurationManager.ConnectionStrings["Conn"].ConnectionString))
    {
        sqlCon.Open();

        foreach (var item in _apiData.Where(d => d.UnemploymentRate > 70))
        {
            // 查询数据库中是否存在同名记录
            using (var checkCmd = new SqlCommand(@"
                SELECT Unemployment FROM tbl_name WHERE Name = @Name", sqlCon))
            {
                checkCmd.Parameters.AddWithValue("@Name", item.Name);
                var dbUnemployment = checkCmd.ExecuteScalar();

                if (dbUnemployment == null)
                {
                    // 插入新记录
                    using (var insertCmd = new SqlCommand(@"
                        INSERT INTO tbl_name (logtime, Latitude, Longitude, Name, Population, Unemployment)
                        VALUES (@LogTime, @Lat, @Long, @Name, @Population, @UnemploymentRate)", sqlCon))
                    {
                        insertCmd.Parameters.AddWithValue("@LogTime", item.LogTime);
                        insertCmd.Parameters.AddWithValue("@Lat", item.Lat);
                        insertCmd.Parameters.AddWithValue("@Long", item.Long);
                        insertCmd.Parameters.AddWithValue("@Name", item.Name);
                        insertCmd.Parameters.AddWithValue("@Population", item.Population);
                        insertCmd.Parameters.AddWithValue("@UnemploymentRate", item.UnemploymentRate);
                        insertCmd.ExecuteNonQuery();
                    }
                }
                else if (Convert.ToDecimal(dbUnemployment) != item.UnemploymentRate)
                {
                    // 更新现有记录的失业率
                    using (var updateCmd = new SqlCommand(@"
                        UPDATE tbl_name 
                        SET logtime = @LogTime,
                            Latitude = @Lat,
                            Longitude = @Long,
                            Population = @Population,
                            Unemployment = @UnemploymentRate
                        WHERE Name = @Name", sqlCon))
                    {
                        updateCmd.Parameters.AddWithValue("@LogTime", item.LogTime);
                        updateCmd.Parameters.AddWithValue("@Lat", item.Lat);
                        updateCmd.Parameters.AddWithValue("@Long", item.Long);
                        updateCmd.Parameters.AddWithValue("@Name", item.Name);
                        updateCmd.Parameters.AddWithValue("@Population", item.Population);
                        updateCmd.Parameters.AddWithValue("@UnemploymentRate", item.UnemploymentRate);
                        updateCmd.ExecuteNonQuery();
                    }
                }
            }
        }
    }
}

4. 主流程调用

在控制台程序的Main方法中调用:

class Program
{
    static void Main(string[] args)
    {
        var controller = new ControllerClass();
        controller.FetchApiData();
        controller.SyncDataToDatabase();
    }
}

三、关键说明

  1. MERGE语句优势:相比逐行处理,MERGE只需一次数据库交互,性能更优,适合大数据量场景
  2. 数据过滤:先过滤出UnemploymentRate>70的记录,减少不必要的数据库操作
  3. 参数化查询:所有SQL操作均使用参数化查询,避免SQL注入风险
  4. 空值判断:添加了_apiData的空值判断,防止空引用异常

内容的提问来源于stack exchange,提问作者StackUseR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 10:35:29