如何防止返回的Json被拆分?

时间:2019-03-23 17:42:41

标签: c# sql-server dapper

我正在使用Dapper从SQL Server读取数据。我有一条返回长Json结果的SQL语句,但问题是该结果被分为3行,每行最多2033个字符,因此Dapper无法解析返回的结果,因为它是无效的Json。

如何防止这种分裂或如何使Dapper应对呢?

这是我的代码:

SqlMapper.ResetTypeHandlers();
SqlMapper.AddTypeHandler(new JsonTypeHandler<List<Product>>());

const string sql = @"SELECT 
                         *,
                         (SELECT * FROM Balance b
                          WHERE p.SKU = b.SKU 
                          FOR JSON PATH) AS [Balances]
                     FROM Product p
                     WHERE SKU IN @SKUs
                     FOR JSON PATH";
var connection = new SqlConnection("myconnection");
return connection.QuerySingleAsync<List<Product>>(sql, new{SKUs = new[] {"foo", "bar"}} });

以及TypeHandler的代码:

public class JsonTypeHandler<T> : SqlMapper.TypeHandler<T>
    {
        public override T Parse(object value)
        {
            return JsonConvert.DeserializeObject<T>(value.ToString());
        }

        public override void SetValue(IDbDataParameter parameter, T value)
        {
            parameter.Value = JsonConvert.SerializeObject(value);
        }
    }

这是我如何在DataGrip中运行此SQL enter image description here 编辑: 这是错误消息:

  

Newtonsoft.Json.JsonSerializationException:反序列化对象时,意外结束。路径'[0] .Balances [4] .WarehouseId',第1行,位置2033。

1 个答案:

答案 0 :(得分:0)

我的解决方案是编写另一种扩展方法,该方法包装如下的Query<string>方法:

public static T QueryJson<T>(this IDbConnection cnn, string sql, object param = null,
        IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null,
        CommandType? commandType = null) where T: class
    {
        var result = cnn.Query<string>(sql, param, transaction, buffered, commandTimeout, commandType).ToList();
        if (!result.Any())
            return default(T);

        // Concats
        var sb = new StringBuilder();
        foreach (var jsonPart in result)
            sb.Append(jsonPart);

        var settings = new JsonSerializerSettings
        {
            // https://github.com/danielwertheim/jsonnet-contractresolvers
            // I use this Contract Resolver to set data to private setter properties
            ContractResolver = new PrivateSetterContractResolver()
        };

        // Using Json.Net to de-serialize objects
        return JsonConvert.DeserializeObject<T>(sb.ToString(), settings);
    }

当查询大数据(1000个对象花费2.7秒而不是1.3秒)时,此解决方案效果很好,并且慢于多重映射方法。