2017-08-31 3 views
2

J'utilise FOR JSON de SQL Server 2016 pour convertir une instruction SQL Server SELECT en une chaîne JSON. Mon intention est que C# convertisse la chaîne JSON produite en un objet.Comment convertir une structure JSON enfant en un graphique d'objet C#

serveur SQL Server instruction select:

SELECT 
    Id AS PersonId, 
    FirstName, 
    LastName, 
    Name, 
    Birthday, 
    (
     SELECT 
      PhoneNumber.PhoneNumberTypeId, 
      PhoneNumber.PhoneNumber    
     FROM    
      PhoneNumber 
      INNER JOIN PhoneNumberType ON PhoneNumber.PhoneNumberTypeId = PhoneNumberType.Id 
     WHERE 
      PhoneNumber.PersonId = Person.Id 
     FOR JSON PATH,INCLUDE_NULL_VALUES  
    ) AS PhoneNumberList 
FROM    
    Person 
ORDER BY 
    LastName 
FOR JSON PATH,INCLUDE_NULL_VALUES 

C# Object Je suis en train de convertir les données en:

public class PersonDataContract : IPersonDataContract 
{ 
    public Int32 PersonId { get; set; } 
    public String FirstName { get; set; } 
    public String LastName { get; set; } 
    public String Name { get; set; } 
    public DateTime? Birthday { get; set; } 
    public Int32 Age { get; } 
    public IList<IPhoneNumberDataContract> PhoneNumberList { get; set; } 

    public PersonDataContract() 
    { 
     PhoneNumberList = new List<IPhoneNumberDataContract>(); 
    } 
} 

Raw JSON:

[ 
    { 
     "PersonId": 5, 
     "FirstName": "Squire", 
     "LastName": "Escrow", 
     "Name": "Squire Escrow", 
     "Birthday": "2001-12-12", 
     "PhoneNumberList": "[{\"PhoneNumberTypeId\":1,\"PhoneNumber\":\"8129091423\"}]" 
    }, 
    { 
     "PersonId": 6, 
     "FirstName": "Vilhelm", 
     "LastName": "Huldsputh", 
     "Name": "Vilhelm Huldsputh", 
     "Birthday": "1953-11-13", 
     "PhoneNumberList": "[{\"PhoneNumberTypeId\":1,\"PhoneNumber\":\"9871237171\"},{\"PhoneNumberTypeId\":2,\"PhoneNumber\":\"8189991212\"}]" 
    } 
] 

conversion de code JSON brut à l'objet:

... 
using (DbDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection)) 
{ 

    while (reader.Read()) 
    { 
     var jsonString = reader.GetValue(0).ToString(); 

     var list = JsonConvert.DeserializeObject<List<PersonDataContract>>(jsonString); 
    } 

    reader.Close(); 
} 

Ce processus fonctionne aussi longtemps que je retire PhoneNumberList de la JSON brut. Je pense que le problème est que j'utilise 2 'FOR JSON PATH dans mon instruction SQL (une pour la PhoneNumberList elle-même et une pour l'instruction SELECT globale) qui provoque la conversion de PhoneNumberList en String qui n'est pas converti en un tableau. Comment convertir la chaîne enfant représentant une collection de numéros de téléphone en un tableau de IPhoneNumberDataContrat?

+3

'... Anniversaire, JSON_QUERY (SELECT ...)'. –

+0

Marquez PhoneNumberList de PersonDataContract en tant que chaîne, puis désérialisez chacune de ces chaînes en PhoneNumberDataContract. –

+0

@JeroenMostert - votre suggestion a résolu le problème. Pouvez-vous répondre à la question s'il vous plaît afin que je puisse l'accepter. Je vous remercie. –

Répondre

1

C'est un peu de couvert the FAQ:

Question. J'ai du texte JSON stocké dans une colonne de table. Je veux l'inclure dans la sortie de FOR JSON. Mais FOR JSON échappe à tous personnages du JSON, donc je suis obtenir une chaîne JSON au lieu d'un objet imbriqué [..]

réponse. JSON stocké dans une colonne de texte ou un littéral est traité comme n'importe quel texte. Autrement dit, il est entouré de guillemets doubles et s'est échappé. Si vous voulez retourner un objet JSON non échappés, passer la colonne JSON comme un argument à la fonction JSON_QUERY [..]

Il ne mentionne pas explicitement que toute sous-requête non trivial qui utilise FOR JSON sera également produire une valeur échappée, et nécessite JSON_QUERY de cette manière. Il faut donc utiliser

SELECT 
    Id AS PersonId, 
    FirstName, 
    LastName, 
    Name, 
    Birthday, 
    JSON_QUERY(
     SELECT 
      ... 
     FOR JSON PATH,INCLUDE_NULL_VALUES  
    ) AS PhoneNumberList 

Par « non négligeable », je veux dire qu'une requête comme cela ne pas besoin JSON_QUERY:

SELECT 
    'Foo' AS Foo, (
     SELECT 1 AS A 
     FOR JSON PATH 
    ) AS Bar 
FOR JSON PATH 

Bar ne seront pas ignorés ici, puisque l'optimiseur se souvient apparemment il est traiter avec JSON. Je n'ai pas encore été en mesure de trouver un ensemble cohérent de règles qui régit ce (different question, same issue), et il n'est même pas clair si c'est un comportement prévu ou un bug, mais JSON_QUERY vous renflouer malgré tout. Il devrait probablement toujours être utilisé, pour éviter les surprises avec une requête allant de "simple" à "complexe" et en ayant soudainement besoin.