0

I have written a batch class where when parent is created then child get created and relate to it. But when I manually create the parent record, child record get create in bulk.

I want when one parent is created then related to it one child should get created.

Below is the code:

Batch

global class ESRT_Batch_Tour_Email_Creation implements Database.Batchable <sObject> {
    List<Leasing_Tour_Email_Queue__c> Lea = new List<Leasing_Tour_Email_Queue__c>();
    
    global Database.QueryLocator start (Database.BatchableContext bc){
        String query = 'SELECT Id,Name,Tour_Date__c from Tour__c';
        return Database.getQueryLocator(query);
    }
    
    global void execute(Database.BatchableContext bc,List<Tour__c> batch) {
        for(Tour__c tou : batch){
            Leasing_Tour_Email_Queue__c t = new Leasing_Tour_Email_Queue__c();
            t.Tour__c = tou.Id;
            Lea.add(t);
        }

        insert lea;
    }

    global void finish(Database.BatchableContext bc) {
        //Do Nothing.
    }
}

Trigger

trigger LeasingTourBatc on Tour__c (after insert) {
    if (Trigger.isAfter && Trigger.isInsert){
       for(Tour__c To : Trigger.new){
           ESRT_Batch_Tour_Email_Creation b = new ESRT_Batch_Tour_Email_Creation();
           Database.executeBatch(b);
       }
    }
}

2 Answers 2

0

There are several problems with the code:

  1. You are queueing one batch per record inserted which I don't think is what you want to achieve (also a bad practice). I assume that you want to enqueue a single batch that will process all the records that have been inserted
  2. Your start() method of the Batch Class has no filtering. It is always querying for all the Tour__c records in the Database which is also incorrect

So, in order to fix this, you need to pass the records to the batch in some way and filter the query to only include the records that have been created. I've updated your code with these suggestions. I'm passing the records through the Constructor of the class.

Trigger

trigger LeasingTourBatc on Tour__c (after insert) {
    if (Trigger.isAfter && Trigger.isInsert){
           ESRT_Batch_Tour_Email_Creation b = new ESRT_Batch_Tour_Email_Creation(Trigger.new);
           Database.executeBatch(b);
       }
    }
}

Batch

global class ESRT_Batch_Tour_Email_Creation implements Database.Batchable <sObject> {

    List<Tour__c> createdTours;

    public ESRT_Batch_Tour_Email_Creation (List<Tour__c> createdTours) {
        this.createdTours = createdTours;
    }
    
    global Database.QueryLocator start (Database.BatchableContext bc){
        String query = 'SELECT Id,Name,Tour_Date__c from Tour__c where Id IN: createdTours';
        return Database.getQueryLocator(query);
    }
    
    global void execute(Database.BatchableContext bc,List<Tour__c> batch) {
        List<Leasing_Tour_Email_Queue__c> Lea = new List<Leasing_Tour_Email_Queue__c>();
        for(Tour__c tou : batch){
            Leasing_Tour_Email_Queue__c t = new Leasing_Tour_Email_Queue__c();
            t.Tour__c = tou.Id;
            Lea.add(t);
        }

        insert lea;
    }

    global void finish(Database.BatchableContext bc) {
        //Do Nothing.
    }
}

)

5
  • Hi Its working Thanks for your sugession Can you advise me on this -I have three object tour, tour visit and Tour Suit . In that Tour is the Parent of Tour Visit and then Tour Visit is the parent of Tour Suit, So in Tour suit there is field Call property Name , I want to retrieve the data from Tour Object Is it possible to Retrieve the Property Name through Tour , How soql query write for this , Please answer :)
    – user105921
    Commented Oct 19, 2021 at 13:01
  • If I understood correctly, you should have a Lookup Field in Tour Suit (let's say its API name is Tour_Visit__c) that relates the Suit to the Visit. You should also have a Lookup Field in Tour Visit (let's call it Tour__c) which relates your Tour Visit to a Tour. So, in a SOQL to the Tour Suit you could access fields from the parent objects (let's say you want the Name fields from the parent objects) like this: [SELECT Name, Tour_Visit__r.Name, Tour_Visit__r.Tour__r.Name]. Commented Oct 19, 2021 at 19:38
  • What i want is that i want to compare that when tour date is less than today date or property name is unique then only child record get created Like below ; Leasing_Tour_Email_Queue__c t = new Leasing_Tour_Email_Queue__c();, So can you sugeest be what can i change in the code How can i compare property name if its not fecth in the SOQL query, Pls help
    – user105921
    Commented Oct 20, 2021 at 8:01
  • Can you please specify in which object you have the Lookup fields and to which exact object they point to? Also, please provide the exact API names of the Lookup fields and also the fields that you want to use to perform the logic (Tour Date, Property Name) Commented Oct 20, 2021 at 15:14
  • Tour_Visit__c have lookup with Property__c and also have a master detail with Tour__c,.....So i have written the query (SELECT Id,Name,Tour_Date__c,(Select id,Property__r.Name From Tour_Visits__r) from Tour__c) Which should give the Tour date and Property name , But how can i check the my criteria which is -tour date is less than today date or property name is unique then only child record get created what update need to be done on coding side
    – user105921
    Commented Oct 21, 2021 at 15:29
0

First of all, if it's a minor 1:1 creation, you probably don't need Batchable. That's for mass updates. Secondly, you've written your query without a filter, so naturally, it will create one child record for every parent in the database each time you create one parent. Further, you're creating one batch per record in the trigger context, so you could end up running a hundred batches in a single trigger. If you really need the extra CPU time, use Queueable for a task of this size. Also, do not use global unless this is for a managed package, and you need subscribers to call it directly. public is the recommended access level for this code.

public class ESRT_Batch_Tour_Email_Creation implements Queueable {
    Tour__c[] tours;
    public ESRT_Batch_Tour_Email_Creation(Tour__c[] records) {
        tours = records;
    }
    public void execute(QueueableContext context) {
        Leasing_Tour_Email_Queue__c[] lea = new Leasing_Tour_Email_Queue__c[0];
        for(Tour__c tou : tours){
            Leasing_Tour_Email_Queue__c t = new Leasing_Tour_Email_Queue__c();
            t.Tour__c = tou.Id;
            Lea.add(t);
        }
        insert lea;
    }    
}

Which would make your trigger:

trigger LeasingTourBatc on Tour__c (after insert) {
    ESRT_Batch_Tour_Email_Creation b = new ESRT_Batch_Tour_Email_Creation(Trigger.new);
    System.enqueueJob(b);
}
1
  • Hi , Thanks for the answer appreciate it, I have one question i have three object tour, tour visit and Tour Suit . In that Tour is the Parent of Tour Visit and then Tour Visit is the parent of Tour Suit, So in Tour suit there is field Call property Name , I want to retrieve the data from Tour Object Is it possible to Retrieve the Property Name through Tour , How soql query write for this , Please answer :)
    – user105921
    Commented Oct 19, 2021 at 12:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .