2017-01-19 8 views
0

Ich deserialisieren JSON in einer Datentabelle mithilfe der folgenden Anweisung in VB.NET.Deserialisieren von JSON in Datentabelle in VB.NET mithilfe von JsonConvert

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

myRecords ist eine JSON-Zeichenfolge.

Es funktioniert gut, aber myRecords hat einige Nummerneigenschaften wie {"PhoneNo": "123456789", "ID": "46541"} und nach der Deserialisierung werden diese Eigenschaften in eine Spalte mit Datentyp als String konvertiert.

Wie kann ich sie in eine Nummer deserialisieren? myRecords wird dynamisch aufgefüllt, daher kann ich nicht hart codieren.

+1

Woher kommt der JSON? Wie sieht es aus? Im Allgemeinen sind Telefonnummern * * Strings: Sie können sie nicht hinzufügen oder subtrahieren, so dass sie keine Zahlen sind. Wenn die ID als Zeichenfolge serialisiert wird, müssen Sie möglicherweise einen Konverter schreiben, um es in int zu erzwingen – Plutonix

Antwort

0

Der Grund, warum Json.NET eine string-typed Spalte für "PhoneNo" : "123456789" erstellt, ist, dass "123456789" tatsächlich ein Zeichenfolgenliteral gemäß der JSON standard ist. Ein numerisches Literal würde so aussehen, ohne doppelte Anführungszeichen um den Wert: 123456789. Sind Sie sicher, dass diese Eigenschaften immer numerische Zeichenfolgen sind? Nicht alle Telefonnummern sind beispielsweise numerisch, so dass es unklug erscheint, sie als solche hart zu codieren.

aber sagen, dass, wenn Sie sicher sind, dass diese Eigenschaften immer numerischen Strings sein und wollen Json.NET numerische DataTable Spalten für sie zu schaffen, müssen Sie es im Voraus die gewünschte Art für diese Spalten erzählen. Eine Option wäre, ein typed DataTable aus einem geeigneten Schema zu erstellen. In diesem Fall wird JsonConvert.DeserializeObject(Of TTypedDataTable)(myRecords) eine DataTable Unterklasse mit den erforderlichen Spaltentypen erstellen.

Eine andere Option wäre, die DataTable manuell mit einem geeigneten Satz von Spalten zu erstellen, dann füllen Sie die Tabelle von Ihrem JSON. Leider funktioniert JsonConvert.PopulateObject() nicht auf einem zuvor zugewiesenen DataTable, so dass Sie DataTableConverter.ReadJson() direkt aufrufen müssen. Dies könnte mit der folgenden Erweiterungsmethode erfolgen:

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 

es dann wie folgt verwenden:

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

Beispiel fiddle.

Sie haben auch geschrieben, Ich kann nicht hart Code. Wenn Sie wirklich nicht im Voraus wissen, welche Spalten mit String-Werten eigentlich als numerische Typen deserialisiert werden sollen, können Sie den JSON vorverarbeiten, indem Sie ihn in eine Jtoken laden und alle Eigenschaftenwerte nach Namen und nach gruppieren Jede Gruppe überprüft, dass alle die Werte in der Gruppe sind Strings, die in Zahlen konvertierbar sind. Wenn alle konvertierbar sind, können Sie die Konvertierung vornehmen. Aber wenn nur einige konvertierbar sind, sollten Sie die Konvertierung nicht vornehmen, da dies den JSON.NET Typ-Inferenzalgorithmus brechen wird. Es kann mit folgenden Erweiterungsmethoden erfolgen:

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 

Dann Vorprozess und deserialisieren wie folgt:

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

Beispiel fiddle #2.

Ich bin mir nicht sicher, ob ich das aber empfehlen würde.Die Tatsache, dass die JSON-Werte Zeichenfolgen sind, legt nahe, dass in der Datenbank, aus der der JSON generiert wurde, diese Werte beliebige Zeichenfolgen sein können. Wenn dies der Fall ist, kann das Hacken in einer Konvertierung zu long später Probleme verursachen, wenn nicht numerische Werte in die Datenbank eingegeben werden.

Verwandte Themen