Recently I have been trying my hand at using the SOAP API (C#) to automate a data-migration between two SFDC instances.
Because the destination instance is still being built, I am trying to use the Partner instead of the Enterprise. The benefit is that I can use the same C# class to handle both sides, and don't need to generate a new Class every time an administrator adds a field (avoiding errors like THIS with each change).
That being said, I was very disapointed with the experience of the Partner API when it came to Accessing sObjects (See Using the Partner WSDL). Specifically not having access to sObject.get(fieldName) or sObject.put(fieldName, value).
It seems that when using Java there is a sObject.getField(fieldName) (see the java example on Page 100 of the SOAP API Documentation) but this doesn't exist in c#.
That being said, I am trying to extend the sObject functionality to add these features. The following seems to work.
namespace sforce{
public partial class sObject{
public dynamic get(string s){
// we use the standard sObject.Any property to iterate over sobject Attributes
for (int i = 0; i < Any.Length; i++){
System.Xml.XmlElement e = Any[i];
if (e.LocalName == s)
if (e.Attributes.Count == 0)
return Any[i].InnerText;
else
return convert(e.ChildNodes);
}
return null;
}
// Create a private method to convert parent Related Objects
private sObject convert(System.Xml.XmlNodeList e){
sObject o = new sObject();
o.type = e[0].InnerText;
System.Xml.XmlElement[] fields = new System.Xml.XmlElement[e.Count - 1];
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
for (int i = 1; i < e.Count; i++){
fields[i - 1] = doc.CreateElement(e[i].LocalName);
fields[i - 1].InnerText = e[i].InnerText;
fields[i - 1].Prefix = e[i].Prefix;
}
o.Any = fields;
return o;
}
}
}
Note: "sforce" above is the namespace I am using for the C# Proxy class generated from the Partner WSDL.
this can then be called as follows:
String soqlQuery = "SELECT Id, FirstName, LastName, AccountId, Account.id, Account.Name FROM Contact";
QueryResult qr = binding.query(soqlQuery);
if (qr.size > 0){
sObject[] records = qr.records;
for (int i = 0; i < records.Length; i++){
sObject con = records[i];
string fName = con.get("FirstName");
sObject account = con.get("Account");
Console.WriteLine("Contact: " + fName);
Console.WriteLine("Account Name: " + account.get("Name") + " : " + account.get("Id");
}
}
My questions here are:
- Is there a native way to have this functionality from C# without having to write it?
- Assuming there isn't, is there a general case where this approach would not work?