3

I am suppose to create a custom Summary object from a base object through MetaData API. The summary object will have some of the fields of the base object and few extra fields.

I could create the Summary Object as well as custom fields of type 'Number','Text','Date','DateTime','Currency' and even 'Formula(Text)'. But if there is any field of type 'MasterDetail' or 'Formula(Number)' the WebService call outs just ignores these fields.

In addition to "fullName, label" from I'm specifying following attributes for the custom field:

For Master-Detail: relationshipLabel, relationshipName,referenceTo and type_x= MasterDetail

For Formula(Number): formula,scale,Precision and type_x=Number

Strange thing is that code executes normally without throwing any ERRORS, which makes it harder for me to resolve the issue.

Appreciate your urgent help.

  • Just wanted to confirm are you calling it from Apex or another language? – Andrew Fawcett Sep 12 '13 at 23:15
  • Can you include a sample of your code? I want to see your approach, are you creating a CustomObject and populating it with a fields collection then calling the 'create' operation on the Metadata API? – Andrew Fawcett Sep 12 '13 at 23:17
  • Yes I am making the MetaService calls from within the Apex controller. Code is bit messy but I hope you'll get the gist of it. The code retrieves all custom fields from a selected object and then creates another object (A Summary Object) picking up some of the fields of the selected object. Here is the link – Aryansh04 Sep 13 '13 at 14:39
  • In the if else part of the getFields method, I have filled up the required attributes for custom field of type "Formula(Number)" and "MasterDetail", still it is not able to create any field of these two types. – Aryansh04 Sep 13 '13 at 14:43
5

Warning: Looking at your code in your controller you are doing a for loop in Apex to attempt pause the execution, i would not recommend this, as its not a reliable way to pause the execution and will (for now) use up the statement governor quickly.

My example below uses the MetadataCreateJob class, to use Batch Apex to handle the async aspect of the Metadata API, it makes calls and reschedules itself to poll the AsyncResult. In a Visualforce context, you should use apex:actionPoller to do the same (take a look at the Visualforce controllers in the library).

Here you go...

    // Define Metadata item to create a Custom Object
    MetadataService.CustomObject customObject = new MetadataService.CustomObject();
    customObject.fullName = 'TestDetail__c';
    customObject.label = 'Test Detail';
    customObject.pluralLabel = 'Test Details';
    customObject.nameField = new MetadataService.CustomField();
    customObject.nameField.type_x = 'Text';
    customObject.nameField.label = 'Test Detail Record';
    customObject.deploymentStatus = 'Deployed';
    customObject.sharingModel = 'ReadWrite';

    // Define Metadata item to create a Custom Formula Field on the above object
    MetadataService.CustomField customField1 = new MetadataService.CustomField();
    customField1.fullName = 'TestDetail__c.FormulaField__c';
    customField1.externalId = false;
    customField1.formula = '42';
    customField1.formulaTreatBlanksAs = 'BlankAsZero';
    customField1.label = 'Formula Field';
    customField1.precision = 18;
    customField1.required = false;
    customField1.scale = 2;
    customField1.type_x = 'Number';
    customField1.unique = false;        

    // Define Metadata item to create a Custom Master Detail Field on the above object
    MetadataService.CustomField customField2 = new MetadataService.CustomField();
    customField2.fullName = 'TestDetail__c.Test__c';
    customField2.externalId = false;
    customField2.label = 'Test';
    customField2.referenceTo = 'Test__c';
    customField2.relationshipLabel = 'Test Children';
    customField2.relationshipName = 'Test_Children';
    customField2.relationshipOrder = 0;
    customField2.type_x = 'MasterDetail';
    customField2.writeRequiresMasterRead = false;

    // Pass the Metadata items to the job for processing
    MetadataCreateJob.run(
        new List<MetadataCreateJob.Item> { 
                new MetadataCreateJob.Item(customObject),                   
                new MetadataCreateJob.Item(new List<MetadataService.Metadata> { customField1, customField2 }, null, true) }, // Set wait to true, to process after object creation
        new MetadataCreateJob.EmailNotificationMetadataAsyncCallback());                                

Tip: The way I determined this was to create the fields in the UI and use Eclipse to download the .object file and inspect the values of the child elements in the field element.

| improve this answer | |
  • I couldn't find anyway to handle synchronization and finally went to loop. Your class MetaDataCreateJob is of great help. Thanks for that. – Aryansh04 Sep 21 '13 at 7:10
  • Your welcome, glad the MetadataCreateJob helped, using actionPoller is pretty straight forward as well if your in a Visualforce world. Good luck and glad this helped! – Andrew Fawcett Sep 21 '13 at 8:53

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.