0

EDITED to include apex Messages

I have created a clone button on a Contact record which is designed to add another object (survey) and its child records (survey questions).

My issue is that i cant seem to get the children records to create (cloning the survey works fine).I have commented out my attempt at cloning the child records!

There is an added complexity to this - I have derived the selection list for the survey on the Visualforce page from the names of certain surveys (those marked with Is_Template__c)

Any help or comments would be greatly appreciated!

VF:

<apex:page controller="surveyBuilderController">

<apex:form >
<apex:selectList value="{!surveySelected}" multiselect="false" size="1">
    <apex:selectOptions value="{!surveyTemplatesOptions}"/>
</apex:selectList>

<apex:selectList value="{!buSelected}" multiselect="false" size="1">
    <apex:selectOption itemLabel="Scentia" itemValue="Scentia"/>
    <apex:selectOption itemLabel="IVY" itemValue="IVY"/>
    <apex:selectOption itemLabel="AIM" itemValue="AIM"/>
</apex:selectList>

<apex:commandButton title="Clone" value="Clone" action="{!cloneSelectedSurvey}"/>
<apex:pageMessages />
<apex:commandButton value="Cancel" action="{!cancel}"/>
</apex:form>
</apex:page>

APEX:

public class surveyBuilderController {

public List <Survey__c> surveyTemplatesList {get;set;}
public List <SelectOption> surveyTemplatesOptions {get;set;}
public String surveySelected {get;set;}
public String buSelected {get;set;}
public Survey__c cloneSelectedSurvey {get;set;}
public ID contactID {get;set;}
public ID newSurveyID {get;set;}

Public surveyBuilderController(){

    contactID = ApexPages.currentPage().getParameters().get('Id');
    surveySelected = '';
    surveyTemplatesOptions = new List<SelectOption>();

    for(Survey__c obj :[SELECT Id, Name,Survey_Name__c FROM Survey__c WHERE Is_template__c =: TRUE]){
        surveyTemplatesOptions.add(new SelectOption(obj.Survey_Name__c,obj.Survey_Name__c));
    }
}

public PageReference cloneSelectedSurvey() {
    Savepoint sp = Database.setSavepoint();
    try {
        cloneSelectedSurvey = new Survey__c(
            Survey_Name__c = surveySelected,
            Business_Unit__c = buSelected,
            Contact__c = contactID,
            Status__c = 'Open',
            is_Template__c = FALSE
        );

        insert(cloneSelectedSurvey);

        List<Survey_Question__c> questions = new List<Survey_Question__c>();
        for (Survey_Question__c que : [Select que.Id, que.name FROM Survey_Question__c que WHERE Survey__c = :surveySelected]) {
            Survey_Question__c newq = que.clone(false,true);
            newq.Survey__c = cloneSelectedSurvey.id;
            newq.Is_Template__c = false;
            questions.add(newq);
        }

        insert questions;

        if (ApexPages.getMessages().size() > 0) return null;
        PageReference cloneSelectedSurvey = new PageReference('/'+cloneSelectedSurvey.Id);
        cloneSelectedSurvey.setRedirect(true);
        return cloneSelectedSurvey;

    }

    catch(System.Exception e) {
        ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR,'Error cloning survey.' + e));
        Database.rollback(sp);
    }
    return null;
}

public PageReference cancel(){
    return new PageReference('/'+contactID);
}
}
  • 1
    When you commented your code, did you move it below your return? Because if not, that would be your problem. – SFDC Neuf Jan 31 '17 at 23:26
  • Thanks SFDC Neuf, I have updated the post above. The code is accepted however no child records are being created. – TheMikeyBoosh Jan 31 '17 at 23:34
  • 1
    Could you move the commented out code to the placement where it was originally? I don't see anything immediately wrong with the commented-out code, so I figured the placement might be the issue. – SFDC Neuf Jan 31 '17 at 23:34
  • 1
    If the problem you are seeing is the "Error cloning questions." message, suggest you append the exception to it 'Error cloning questions.' + e that may provide more detail of the problem. Also suggest you post the exact code and exactly what you see in the question; the code currently posted doesn't make much sense. – Keith C Jan 31 '17 at 23:38
  • 1
    One other thing - what is the value of surveySelected? Is it a name or an Id? When you query, Survey_Question__c.Survey__c is looking for an Id. – SFDC Neuf Feb 2 '17 at 16:22
4

You are returning the parent and redirecting to another page before creating and inserting the children. Try this:

public class surveyBuilderController {

public List <Survey__c> surveyTemplatesList {get;set;}
public List <SelectOption> surveyTemplatesOptions {get;set;}
public String surveySelected {get;set;}
public String buSelected {get;set;}
public Survey__c cloneSelectedSurvey {get;set;}
public ID contactID {get;set;}
public ID newSurveyID {get;set;}
private Map<Id, Survey__c> surveyMap;

Public surveyBuilderController(){

    contactID = ApexPages.currentPage().getParameters().get('Id');
    surveySelected = '';
    surveyTemplatesOptions = new List<SelectOption>();
    surveyMap = new Map<Id, Survey__c>([SELECT Id, Name,Survey_Name__c FROM Survey__c WHERE Is_template__c =: TRUE]);

    for(Survey__c obj : surveyMap.values()){
        surveyTemplatesOptions.add(new SelectOption(obj.Id,obj.Survey_Name__c));
    }
}

public PageReference cloneSelectedSurvey() {
    Savepoint sp = Database.setSavepoint();
    try {
        cloneSelectedSurvey = new Survey__c(
            Survey_Name__c = surveyMap.get(surveySelected).Survey_Name__c,
            Business_Unit__c = buSelected,
            Contact__c = contactID,
            Status__c = 'Open',
            is_Template__c = FALSE
        );

        insert(cloneSelectedSurvey);

        List<Survey_Question__c> questions = new List<Survey_Question__c>();
         for (Survey_Question__c que : [Select que.Id, que.name FROM Survey_Question__c que WHERE Survey__c = :surveySelected]) {
            Survey_Question__c newq = que.clone(false);
            newq.Survey__c = cloneSelectedSurvey.id;
            questions.add(newq);
        }
        insert questions;

        PageReference cloneSelectedSurvey = new PageReference('/'+cloneSelectedSurvey.Id);
        cloneSelectedSurvey.setRedirect(true);
        return cloneSelectedSurvey;

    }
    catch(System.Exception e) {
        ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR,'Error cloning survey.'));
        Database.rollback(sp);
    }
    return null;
}

I also added a savepoint/rollback in there so that if you have an error inserting the children, the parent won't be created.

EDIT: You're also not setting surveySelected to the survey's Id. Changed your SelectOption definition above.

EDIT 2 Updated code above to include changes to correctly set survey name.

  • Thanks for the clean-up! Unfortunately the child records aren't being created... – TheMikeyBoosh Feb 1 '17 at 0:08
  • Thanks for the updated answer. The only issue i have with this is that i purposely selected obj.Survey_Name__c,obj.Survey_Name__c was because when the new survey is created, the name is an id value, not the string value. I need to get the syntax for Survey_Name__c = surveySelected (.survey_name)? – TheMikeyBoosh Feb 2 '17 at 23:46
  • 1
    To do that, save the surveys you query for in a map - edited answer above. – SFDC Neuf Feb 2 '17 at 23:49
  • That's a terrific, comprehensive answer!! I truly owe you a beer!! – TheMikeyBoosh Feb 3 '17 at 0:13
0

EDIT: SFDC Neuf's answer is cleaner and more complete.


The problem is that is the after the survey is inserted you are returning the new PageReference. The the code that clones the survey questions is never being called. Also to help find issues like this you can add debug statements.

Below is corrected code, with a couple of debug statements. Note: This is only the method that is not working.

public PageReference cloneSelectedSurvey() {
    PageReference returnValue;
    try {
        cloneSelectedSurvey = new Survey__c(
            Survey_Name__c = surveySelected,
            Business_Unit__c = buSelected,
            Contact__c = contactID,
            Status__c = 'Open',
            is_Template__c = FALSE
        );

        insert(cloneSelectedSurvey);
        System.Debug('Cloned Survey inserted');
        PageReference cloneSelectedSurvey = new PageReference('/' + cloneSelectedSurvey.Id);
        cloneSelectedSurvey.setRedirect(true);
        returnValue = cloneSelectedSurvey;

    } catch (System.Exception e) {
        ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR, 'Error cloning survey.'));
    }


    try {
        System.Debug('Starting Survey question cloning.');
        List<Survey_Question__c> questions = new List<Survey_Question__c>();
        for (Survey_Question__c que : [Select que.Id, que.name FROM Survey_Question__c que WHERE Survey__c = :surveySelected]) {
            Survey_Question__c newq = que.clone(false);
            newq.Survey__c = cloneSelectedSurvey.id;
            questions.add(newq);
        }
        insert questions;
        System.Debug('Questions cloned.');

    } catch (System.Exception e) {
        returnValue=null;
        ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR, 'Error cloning questions.'));
    }
    return returnValue;
}
  • This code has a major flaw: If the children are inserted, the parent will still be created, and the user will still be linked to the parent's detail page. It does do one thing my answer does not do, which is separate error handling between the two inserts. – SFDC Neuf Jan 31 '17 at 23:51
  • Yes, you are correct. I simply moved the return statement. Your answer is the better answer to this question as this code has other issues. – Fred B Jan 31 '17 at 23:53
  • I changed it so if the questions have an error cloning the user is not re-directed to the new record. – Fred B Jan 31 '17 at 23:56
0

Add an apex:pageMessages to the page that has the clone button and this:

insert questions;

// If there are validation error messages stay on the page so they can be seen
if (ApexPages.getMessages().size() > 0) return null;

in case some validation is causing the insert to fail.

  • Hi Keith, unfortunately there are no errors. There is no validation on both the objects, they are both fairly bare – TheMikeyBoosh Feb 1 '17 at 22:29
  • @TheMikeyBoosh Pity, the mystery continues... – Keith C Feb 1 '17 at 22:34
0

I wrote a generic utility library called SObjectDeepClone for cloning SObjects and their children.

Here's an example of how to use it:

Id leadIdToClone = '00Q3A00000Q0su7';
SObjectDeepClone cloner = new SObjectDeepClone(
    leadIdToClone,
    new Set<String>{ //child relationships to clone
        'Tasks'
    }
);
Lead beforeClone = (Lead) cloner.clone;
beforeClone.LastName = beforeClone.LastName + ' Copy';
Id clonedLeadId = cloner.save();

System.debug(clonedLeadId);

This doesn't solve the issue with the posted question, but since I ended up here based on the title alone, I felt this might help others.

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.