2017-01-19 3 views
0

Я десериализую JSON в таблицу данных, используя инструкцию ниже в VB.NET.Deserialize JSON в таблицу данных в VB.NET с использованием JsonConvert

Dim _dt As DataTable = JsonConvert.DeserializeObject(Of DataTable)(myRecords) 

myRecords - это строка JSON.

Он работает нормально, но myRecords имеет некоторые свойства, такие как {«PhoneNo»: «123456789», «ID»: «46541»}, и после десериализации эти свойства преобразуются в столбец с типом данных в виде строки.

Как я могу десериализовать их в число? myRecords становится динамически заполненным, поэтому я не могу жестко кодировать.

+1

Откуда берутся json? как это выглядит? Обычно номера телефонов * являются * строками: вы не можете их добавить или вычесть, чтобы они не были цифрами. Если идентификатор сериализуется как строка, вам, возможно, придется написать преобразователь, чтобы заставить его int – Plutonix

ответ

0

Причина, по которой Json.NET создает колонку с типизированной строкой для "PhoneNo" : "123456789", состоит в том, что "123456789" является, по сути, строковым литералом в соответствии с JSON standard. Числовой литерал будет выглядеть так, без двойных кавычек вокруг значения: 123456789. Вы уверены, что эти свойства будут всегда быть числовыми строками? Не все телефонные номера являются числовыми, например, поэтому представляется неразумным, чтобы их жестко кодировать как таковые.

Это, как говорится, если вы уверены, что эти свойства будут всегда числовые строки и хотите Json.NET создавать числовые DataTable столбцы для них, вы должны сказать ему заранее желаемого типа для этих столбцов. Один из вариантов - создать typed DataTable из соответствующей схемы. В этом случае JsonConvert.DeserializeObject(Of TTypedDataTable)(myRecords) создаст подкласс DataTable с необходимыми типами столбцов.

Другой вариант - создать команду DataTable вручную с соответствующим набором столбцов, а затем заполнить таблицу из вашего JSON. К сожалению, JsonConvert.PopulateObject() не будет работать в предварительно размещенном DataTable, поэтому вам нужно позвонить напрямую DataTableConverter.ReadJson(). Это может быть сделано с помощью следующего метода расширения:

Public Module JsonExtensions 
    Public Sub PopulateDataTable(json As String, target As DataTable, Optional settings As JsonSerializerSettings = Nothing) 
     Using reader = New JsonTextReader(New StringReader(json)) 
      Do 
       If reader.TokenType = JsonToken.StartArray Then 
        ' Populate the table 
        Dim converter = New DataTableConverter() 
        converter.ReadJson(reader, target.GetType(), target, JsonSerializer.CreateDefault(settings)) 
       End If 
      Loop While reader.Read() 
     End Using 
    End Sub 
End Module 

затем использовать его следующим образом:

 Dim _dt = New DataTable() 
     _dt.Columns.Add("PhoneNo", GetType(Long)) 
     _dt.Columns.Add("ID", GetType(Long)) 
     JsonExtensions.PopulateDataTable(myRecords, _dt) 

Пример fiddle.

Вы также написали, Я не могу жестко кодировать. Если вы действительно не знаете заранее, какие столбцы со строковыми значениями следует фактически десериализовать как числовые типы, то вы можете сделать предварительную обработку JSON, загрузив его в Jtoken, группируя все значения свойств по имени и для каждая группа, проверяя, что все значениями в группе являются строки, которые могут быть конвертированы в числа. Если все конвертируемые, вы можете сделать преобразование. Но если только конвертируемые, вы не должны делать преобразование, так как это нарушит алгоритм вывода типа Json.NET. Это может быть сделано с помощью следующих методов расширения:

Public Module JsonExtensions 
    Private ReadOnly NumberTypes = New JTokenType() {JTokenType.[Integer], JTokenType.Float, JTokenType.[String], JTokenType.Comment, JTokenType.Raw, JTokenType.[Boolean]} 

    Private Function ValidateToken(o As JToken, validTypes As JTokenType(), nullable As Boolean) As Boolean 
     Return (Array.IndexOf(validTypes, o.Type) <> -1) OrElse (nullable AndAlso (o.Type = JTokenType.Null OrElse o.Type = JTokenType.Undefined)) 
    End Function 

    <System.Runtime.CompilerServices.Extension> _ 
    Public Function CanConvertToNullableLong(token As JToken) As Boolean 
     ' Reverse engineered from 
     ' public static explicit operator long?(JToken value) 
     ' https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Linq/JToken.cs#L1045 
     If token Is Nothing OrElse token.Type = JTokenType.Null OrElse token.Type = JTokenType.Boolean Then 
      Return True 
     End If 
     If Not ValidateToken(token, NumberTypes, True) Then 
      Return False 
     End If 
     Dim jValue = TryCast(token, JValue) 
     If jValue Is Nothing Then 
      Return False 
     End If 
     If TypeOf jValue.Value Is BigInteger Then 
      Dim i = CType(jValue.Value, BigInteger) 
      Return i <= Long.MaxValue AndAlso i >= Long.MinValue 
     End If 
     Dim s = CType(jValue, String) 
     Dim v As Long 
     Return Long.TryParse(s, NumberStyles.Number, NumberFormatInfo.InvariantInfo, v) 
    End Function 

    Public Sub TryConvertColumnsToNullableLong(root As JToken) 
     If TypeOf root Is JContainer Then 
      ' If ALL columns values of a given name can be converted from string to long, then do so. 
      ' Do not convert columns where some but not all are convertable. 
      For Each group In DirectCast(root, JContainer) _ 
       .Descendants() _ 
       .OfType(Of JProperty)() _ 
       .GroupBy(Function(p) p.Name) _ 
       .Where(Function(g) g.All(Function(p) (p.Value.Type = JTokenType.String Or p.Value.Type = JTokenType.Null) AndAlso p.Value.CanConvertToNullableLong())) 
       For Each p In group 
        p.Value = CType(p.Value, System.Nullable(Of Long)) 
       Next 
      Next 
     End If 
    End Sub 
End Module 

Тогда предобработки и десериализации следующим образом:

 Dim token = JToken.Parse(myRecords) 
     JsonExtensions.TryConvertColumnsToNullableLong(token) 
     Dim _dt = token.ToObject(Of DataTable)() 

Пример fiddle #2.

Я не уверен, что рекомендовал бы это.Тот факт, что значения JSON являются строками, предполагает, что в базе данных, из которой был создан JSON, эти значения могут быть произвольными строк. Если это так, взлом в преобразовании в long может вызвать проблемы позже, когда в базу данных начнут вводиться нечисловые значения.

Смежные вопросы