2012-09-17 33 views
8

Ho una risposta Json che ricevo da una chiamata API. Ha diversi livelli nidificati come mostrato di seguito (questo è un frammento):Query JSON con LINQ

"Items": [ 
    { 
    "Result": { 
     "Id": "191e24b8-887d-e111-96ec-000c29128cee", 
     "Name": "Name", 
     "StartDate": "2012-04-03T00:00:00+01:00", 
     "EndDate": null, 
     "Status": { 
     "Name": "Active", 
     "Value": 5 
     }, 
     "Client": { 
     "Id": "35ea10da-b8d5-4ef8-bf23-c829ae90fe60", 
     "Name": "client Name", 
     "AdditionalItems": {} 
     }, 
     "ServiceAgreement": { 
     "Id": "65216699-a409-44b0-8294-0e995eb05d9d", 
     "Name": "Name", 
     "AdditionalItems": { 
      "ScheduleBased": true, 
      "PayFrequency": { 
      "Id": "981acb72-8291-de11-98fa-005056c00008", 
      "Name": "Weekly", 
      "AdditionalItems": {} 
      }, 
      "PayCycle": [ 
      { 
       "Name": "Schedule Based", 
       "ScheduleBased": true, 
       "SelfBilling": false, 
       "Id": "a8a2ecc4-ff79-46da-a135-743b57808ec3", 
       "CreatedOn": "2011-09-16T23:32:19+01:00", 
       "CreatedBy": "System Administrator", 
       "ModifiedOn": "2011-09-16T23:32:19+01:00", 
       "ModifiedBy": "System Administrator", 
       "Archived": false 
      } 
      ] 
     } 
     }, 
} 
] 
... 

Quello che voglio fare è retreive i dati dal nodo PayCycle utilizzando LINQ. Posso ad esempio ottenere gli oggetti con un valore true utilizzando Result.ServiceAgreement.AdditionalItems.SchedultedBased utilizzando il seguente Linq nel controller:

var result = from p in data["Data"]["Items"].Children() 
      where (bool)p["Result"]["ServiceAgreement"]["AdditionalItems"]["ScheduleBased"] == true 
      select new 
      { 
       Name = (string)p["Result"]["Client"]["Name"], 
       Id = (string)p["Result"]["Client"]["Id"] 
      }; 

Ora ho bisogno di ottenere Result.ServiceAgreement.AdditionalItems.Paycycle.ScheduleBased e SelfBilling proprietà. Come faccio a fare questo se PayCycle è anche un array, come faccio ad avere i figli come ho fatto con Data.Items nel Linq sopra in modo che possa avere il filtro della clausola where su entrambi questi elementi?

risposta

12

È possibile deserializzare il JSON in un oggetto dynamic, e quindi utilizzare LINQ to Objects:

[TestMethod] 
    public void TestMethod1() 
    { 
     const string json = @"""Items"": [ 
{ 
""Result"": { 
    ""Id"": ""191e24b8-887d-e111-96ec-000c29128cee"", 
    ""Name"": ""Name"", 
    ""StartDate"": ""2012-04-03T00:00:00+01:00"", 
    ""EndDate"": null, 
    ""Status"": { 
    ""Name"": ""Active"", 
    ""Value"": 5 
    }, 
    ""Client"": { 
    ""Id"": ""35ea10da-b8d5-4ef8-bf23-c829ae90fe60"", 
    ""Name"": ""client Name"", 
    ""AdditionalItems"": {} 
    }, 
    ""ServiceAgreement"": { 
    ""Id"": ""65216699-a409-44b0-8294-0e995eb05d9d"", 
    ""Name"": ""Name"", 
    ""AdditionalItems"": { 
     ""ScheduleBased"": true, 
     ""PayFrequency"": { 
     ""Id"": ""981acb72-8291-de11-98fa-005056c00008"", 
     ""Name"": ""Weekly"", 
     ""AdditionalItems"": {} 
     }, 
     ""PayCycle"": [ 
     { 
      ""Name"": ""Schedule Based"", 
      ""ScheduleBased"": true, 
      ""SelfBilling"": false, 
      ""Id"": ""a8a2ecc4-ff79-46da-a135-743b57808ec3"", 
      ""CreatedOn"": ""2011-09-16T23:32:19+01:00"", 
      ""CreatedBy"": ""System Administrator"", 
      ""ModifiedOn"": ""2011-09-16T23:32:19+01:00"", 
      ""ModifiedBy"": ""System Administrator"", 
      ""Archived"": false 
     } 
     ] 
    } 
    } 
} 
} 
]"; 
     dynamic data = System.Web.Helpers.Json.Decode("{" + json + "}"); 

     var result = from i in (IEnumerable<dynamic>)data.Items 
        where i.Result.ServiceAgreement.AdditionalItems.ScheduleBased == true 
        select new 
          { 
           i.Result.Client.Name, 
           i.Result.Client.Id 
          }; 

     Assert.AreEqual(1, result.Count()); 
     Assert.AreEqual("client Name", result.First().Name); 
     Assert.AreEqual("35ea10da-b8d5-4ef8-bf23-c829ae90fe60", result.First().Id); 
    } 

Si noti che ho dovuto aggiungere parentesi {e} attorno alla stringa di esempio JSON, oppure il .NET parser json non mi piace.

+0

Ho modificato leggermente il mio poiché la raccolta PayCycle restituirà solo 1 elemento nella raccolta. Quindi, per esempio, per ottenere la proprietà SelfBilling, ho fatto quanto segue nella clausola where: where (bool) p ["Result"] ["ServiceAccordo"] ["AdditionalItems"] ["PayCycle"] [0] ["SelfBilling"] == false. Questo mi dà il risultato che sto cercando. – KDee

0

Per iniziare, non ho familiarità con la scrittura di LINQ/LAMBDA utilizzando questo formato ["alcuni"] ["cosa"]. Il mio primo passo sarebbe quello di creare alcune classi/oggetti per ospitare i dati in modo da facilitare la creazione di qualsiasi codice in seguito.

ad es.

public class Result 
{ 
    public Guid Id { get; set; } 
    public string Name { get; set; }, 
    public DateTime StartDate { get; set; } 
    //you get the idea 
} 

Ma possibilmente provare quanto segue?

var result = from p in data["Data"]["Items"].Children() 
       where (bool)p["Result"]["ServiceAgreement"]["AdditionalItems"]["ScheduleBased"] == true 
        && (p["Result"]["ServiceAgreement"]["AdditionalItems"]["PayCycle"]).Where(o => o.["ScheduleBased"] == true) 
       select new 
       { 
        Name = (string)p["Result"]["Client"]["Name"], 
        Id = (string)p["Result"]["Client"]["Id"] 
       };