Simon Fell > Its just code > What the hell, why are there 2 Ids ?

Tuesday, July 25, 2006

This question comes up every now and then, someone takes a look at the response from the salesforce.com API query call and notices that Id is in there twice, its broke, come on, fix it already, damn on-demand slackers! e.g.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:partner.soap.sforce.com" xmlns:sf="urn:sobject.partner.soap.sforce.com">
<soapenv:Body>
 <queryResponse>
  <result xsi:type="QueryResult">
   <done>true</done>
   <queryLocator xsi:nil="true"/>
   <records xsi:type="sf:sObject">
    <sf:type>Contact</sf:type>
    <sf:Id>00330000004AAvsAAG</sf:Id>
    <sf:Id>00330000004AAvsAAG</sf:Id>
    <sf:LastName>Barr</sf:LastName> 
    <sf:FirstName>Tim</sf:FirstName>
    <sf:AccountId>00130000002g9wOAAQ</sf:AccountId>
   </records>
  <size>1</size>
</result></queryResponse></soapenv:Body></soapenv:Envelope>

Actually, what's going is is that the Id is suposed to be there twice, it makes more sense once you've looked at the WSDL, which defines sObject as

<complexType name="sObject">
  <sequence>
    <element name="type" type="xsd:string"/>
    <element name="fieldsToNull" type="xsd:string" nillable="true" minOccurs="0" maxOccurs="unbounded"/> 
    <element name="Id" type="tns:ID" nillable="true"/>
    <any namespace="##targetNamespace" minOccurs="0" maxOccurs="unbounded" processContents="lax"/>
  </sequence>
</complexType>

The first Id element is there to populate the explicit Id element in the sObject definition, the 2nd Id is there because you included it in the field list for your query (in this case the query was select id, firstname, lastname, accountId from contact where ....) We do this so that the any collection (the collection of elements that are mapped into the any element in the schema, and are typically exposed as an array of elements in the toolkits) contains exactly one element for every field you asked for in the query, and they're in the order you specified in your query, this makes it easier on the client to index into the array and grab the exact data they're expecting, without having to map the elements back to a dictionary to look them up by name. On the downside, if you're using a tool that's not driven by the WSDL, then this can cause all sorts of confusion. Its interesting (and annoying) to note how the tools and machinations of schema mean you end up distorting the messages you generate, If you were ignoring WSDL, Schema and the WS tools, the response would actually be something more like this.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="urn:partner.soap.sforce.com">
<soapenv:Body>
 <queryResult>
   <size>1</size>
   <done>true</done>
   <record>
    <type>Contact</type>
    <Id>00330000004AAvsAAG</Id>
    <LastName>Barr</LastName> 
    <FirstName>Tim</FirstName>
    <AccountId>00130000002g9wOAAQ</AccountId>
   </record>
</queryResult></soapenv:Body>

I think the thing that's really going to bug me down the road is the fact that each generation of tooling will want a different set of tweaks, and what works today for Axis 1.x and .NET 1.x isn't going to work for Axis 3.0 and Indigo II, will the tools ever save me, or just send me to the funny farm to drink coffee all day?