Sunday, February 27, 2011

Salesforce REST API Query Deserialization


In my last article about the Salesforce REST API I showed how to query for records. The JSON encoded result of the query looks something like this:

{
"totalSize" : 2,
"done" : true,
"records" : [ {
"attributes" : {
"type" : "Account",
"url" : "/services/data/v20.0/sobjects/Account/0017000000Q9SFkAAN"
},
"Id" : "0017000000Q9SFkAAN",
"AccountNumber" : "12345",
"Name" : "Big Account"
}, {
"attributes" : {
"type" : "Account",
"url" : "/services/data/v20.0/sobjects/Account/0017000000O1LiGAAV"
},
"Id" : "0017000000O1LiGAAV",
"AccountNumber" : "6789",
"Name" : "Small Account"
}]
}


The next question is how to de-serialize this back into an object. Like I have shown before we can use the JavaScriptSerializer class in the .NET Framework to do this, but what would the object model have to look like? One way we could do it is like this:

public class sfdcAttributes
{
    public string Type { get; set; }
    public string Url { get; set; }
}


public class sfdcAccount
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string AccountNumber { get; set; }

    public sfdcAttributes Attributes { get; set; }    
}

public class sfdcAccountCollection
{
    public bool Done { get; set; }
    public int TotalSize { get; set; }
    public string nextRecordsUrl { get; set; }
    public List<sfdcAccount> Records { get; set; }
}


This will work but it has two problems. First we would have to create a collection class for each SFDC object we want to work with and most of the code for that class would be duplicated from one object to the next. The second problem is that because we put the Attributes property in the sfdcAccount class we can’t use it do do inserts or updates since Attributes isn’t a property on the Account object.


To solve the first problem we can use generics:

public class sfdcCollection<T>
{
    public bool Done { get; set; }
    public int TotalSize { get; set; }
    public string nextRecordsUrl { get; set; }
    public List<T> Records { get; set; }
}


This is a generic SFDC collection class that we can use with any type of object. To solve the second problem we need to pull out the Attributes property. Here is a way to handle that:

public class sfdcAccountForCollection : sfdcAccount
{
    public sfdcAttributes Attributes { get; set; }

}


Here we create a class just for use with the collections that are returned by the query function. We inherit from the base sfdcAccount class so it keeps this additional class very simple. To use these classes to de-serialize the JSON response, we just do this:

sfdcCollection<sfdcAccountForCollection> accts = ser.Deserialize<sfdcCollection<sfdcAccountForCollection>>(json);

No comments: