Как предотвратить возвращение вернувшегося Json? - PullRequest
5 голосов
/ 23 марта 2019

Я использую Dapper для чтения данных с SQL Server.У меня есть оператор SQL, который возвращает длинный результат Json, но проблема заключается в том, что этот результат разбивается на 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);
        }
    }

А вот как я запускаю этот SQL в DataGrip enter image description here Редактировать: Вот сообщение об ошибке:

Newtonsoft.Json.JsonSerializationException: неожиданный конец, когдадесериализация объекта.Путь '[0]. Балансы [4] .WarehouseId', строка 1, позиция 2033.

1 Ответ

0 голосов
/ 17 апреля 2019

Мое решение - написать другой метод расширения, который включает 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 секундами).

...