7

I'm in the process of doing some development in a random1 client org where they want an integration with another parties managed package.

Part of this is to run SOQL queries against custom objects and fields from the managed package.

As part of my testing I was running the following query successfully in the Developer Console Query Editor.

Select Id, SBQQ__Primary__c, SBQQ__Opportunity__c from SBQQ__Quote__c

Yet when I tried to use the same SOQL query from a new Apex class it wouldn't save with the message:

No such column 'SBQQ__Opportunity__c' on entity 'SBQQ__Quote__c'. If you are attempting to use a custom field, be sure to append the '__c' after the custom field name. Please reference your WSDL or the describe call for the appropriate names.

Odd, as I can clearly see this field in the describeSObject Metadata for SBQQ__Quote__c (which is how I built up the SOQL query).

      <fields>
           <aggregatable>true</aggregatable>
           <autoNumber>false</autoNumber>
           <byteLength>18</byteLength>
           <calculated>false</calculated>
           <cascadeDelete>true</cascadeDelete>
           <caseSensitive>false</caseSensitive>
           <createable>true</createable>
           <custom>true</custom>
           <defaultedOnCreate>false</defaultedOnCreate>
           <deprecatedAndHidden>false</deprecatedAndHidden>
           <digits>0</digits>
           <filterable>true</filterable>
           <groupable>true</groupable>
           <idLookup>false</idLookup>
           <inlineHelpText>Opportunity being quoted.</inlineHelpText>
           <label>Opportunity</label>
           <length>18</length>
           <name>SBQQ__Opportunity__c</name>
           <nameField>false</nameField>
           <namePointing>false</namePointing>
           <nillable>false</nillable>
           <permissionable>false</permissionable>
           <precision>0</precision>
           <queryByDistance>false</queryByDistance>
           <referenceTo>Opportunity</referenceTo>
           <relationshipName>SBQQ__Opportunity__r</relationshipName>
           <relationshipOrder>0</relationshipOrder>
           <restrictedPicklist>false</restrictedPicklist>
           <scale>0</scale>
           <soapType>tns:ID</soapType>
           <sortable>true</sortable>
           <type>reference</type>
           <unique>false</unique>
           <updateable>false</updateable>
        </fields>

Note that deprecatedAndHidden is false.

The field section from the sObject Metadata is similar:

  <fields>
    <fullName>SBQQ__Opportunity__c</fullName>
    <deprecated>false</deprecated>
    <description>Opportunity being quoted.</description>
    <externalId>false</externalId>
    <inlineHelpText>Opportunity being quoted.</inlineHelpText>
    <label>Opportunity</label>
    <referenceTo>Opportunity</referenceTo>
    <relationshipLabel>Quotes</relationshipLabel>
    <relationshipName>Quotes</relationshipName>
    <relationshipOrder>0</relationshipOrder>
    <reparentableMasterDetail>false</reparentableMasterDetail>
    <trackHistory>false</trackHistory>
    <trackTrending>false</trackTrending>
    <type>MasterDetail</type>
    <writeRequiresMasterRead>false</writeRequiresMasterRead>
  </fields>

The Custom Object pages make it clearer that the field is no longer part of the active package. Deprecated field

From the Quote Custom Field detail page it is very clearly deprecated2. Available in Versions

How can I tell via the APIs (preferably describeSObject) that a field is deprecated in the managed package that defined it?

Update: I think I need something like the Package Version Header used by the REST API so I can indicate the specific version of the namespace I'm interested in. There is an equivalent header for the Partner WSDL - Package Versions and the Partner WSDL


1 Random as in not my regular orgs, I didn't just log into any org I could to start writing Apex)

2 I'm aware I could alter the Version Settings on the class/trigger in question to the older version of the managed package to access the field. However, that isn't my objective.

  • 2
    Hmm..Seems this may not be a way - deprecatedAndHidden is Reserved for future use - Unfortunately not sure what that way would be though. – Eric May 9 '17 at 2:19
  • @Eric I'm guessing it didn't align with how they are actually deprecating the managed fields against specific package versions. With the Apex to managed package version association only existing in the version settings it can't appear in the describe metadata. At least not without a new structure to describe it correctly. – Daniel Ballinger May 9 '17 at 2:22
  • Well said. I was thinking that but it was all jumbled in my head lol...I am curious if you had v22.0 installed at one point and upgraded to where you are if the query would have worked... – Eric May 9 '17 at 2:23
  • @Eric I had several attempts at writing that comment out :). I think Apex could query the deprecated field if I roll the Version Settings on the Apex class back. In fact, give me a second to try it. – Daniel Ballinger May 9 '17 at 2:25
  • @Eric After rolling the Apex Class version settings against the managed package back to v22.0 I could query the deprecated field. I think as long as that version setting was unchanged there wouldn't have been a problem (at least with saving the Apex class) – Daniel Ballinger May 9 '17 at 2:33
0

I don't think there is flag or field in metadata that give us this particulate information.

Considering above fact we will need to need to depend on workarounds.

One of such workaround is using the Package version number. We can query the installed package version number using following query.

SELECT DurableId, Id, IsSalesforce,MajorVersion,MinorVersion, Name,NamespacePrefix FROM Publisher where Name =:p_name limit 1

Once we get the MajorVersion/MinorVersionnumber its just matter of adding if condition around your SOQL for ex:

Publisher p = [SELECT DurableId, Id, IsSalesforce,MajorVersion,MinorVersion, Name,NamespacePrefix FROM Publisher where Name =:p_name limit 1];  

if(p.MajorVersion > X && p.MinorVersion >Y){  
    //SOQL with SBQQ__Opportunity__c 
}else
{
    //SOQL with SBQQ__Opportunity2__c 
}

If you want make it more sophisticated you can use custom setting decide for which version which SOQL should be used.

Edit 1: We can even go further with dynamic apex and make it easy to maintain. Note that i am not saying "its maintenance free" but its easy to maintain

We can store query in custom setting for each version. Here is sudo code that should do the magic :

Publisher p = [SELECT DurableId, Id, IsSalesforce,MajorVersion,MinorVersion, Name,NamespacePrefix FROM Publisher where Name =:p_name limit 1];  
String ver_number = p.MajorVersion + '.'+  p.MinorVersion

String queryString = '';

List<VerionSoql__C> vsl  = VerionSoql__C.getall().values();

for(VerionSoql__C vs : vsl)
    if(vs.ver__c == ver_number) {
        String queryString = vs.query__c; // Dynamically get the query for the current version 
        break;
    }
}
list<SBQQ__Quote__c> lst = Database.query(queryString);

for(SBQQ__Quote__c o : lst)
    System.debug('>>>' + childRecord.get('SBQQ__Opportunity__c'); // Dynamically get the field value
    System.debug('>>>' + childRecord.get('SBQQ__Opportunity2__c'); // Dynamically get the field value
}

Note 2 important things

  1. We will need to maintain the custom list of SOQL queries for each version. We can automate this using InstallHandler but again this class will need to be updated for each deprecation.
    1. above code is just sudo code and so there can be few syntax error but i am 100 sure that logic will work.
  • Any ideas on how to make it more defensive with less maintenance ? Consider you write the code when package is at version 2.0. Then it is upgraded to 2.5. If you limit to 2.0 in your code (like in your answer) then your code will not do what you want beyond 2.0 even though the field may still be present. Then lets assume that in 3.0 the field is removed. If you did not limit before you would get an error......This is the conundrum I believe the OP (and certainly myself) is observing.... – Eric May 9 '17 at 22:11
  • just updated my answer to show we can use dynamic apex without any error. – AtulRajguru9 May 10 '17 at 5:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.