-1

Write a trigger on the Account object that updates all related Contacts and Opportunities upon saving. When an account is getting updated:

1. All its related contacts should be populate the description field with:

Contact Updated

2. All its related opportunities should be populate the description field with:

Opportunity Updated.

Trigger so far:

trigger trig1 on Account (after update) {

 Set<Id> opportunityIds = new Set<Id>();

 for(Account acc: Trigger.new)
 {
     opportunityIds.add(acc.OpportunityId);
 }

 //Update Opportunities

 Map<ID, Opportunity> mapOpportunity = 
    new Map<ID, Opportunity>([SELECT Id, Opportunity__c 
                    FROM Opportunity 
                            WHERE Id IN :OpportunityIds]);

 List<Opportunity> lstOppToUpdate = new List<Account>();

 for(Account acc : Trigger.new)
 {
   Opportunity opp = mapOpportunity.get(acc.OpportunityId);
   opp.Opportunity__c =  acc.Account__c
   lstoppToUpdate.add(opp);
  }

  update oppToUpdate;

  Map<Id, Opportunity> mapUpdatedOpportunity = new Map<Id,Opportunity>();

 for(Opportunity opp : lstoppToUpdate)
 {
    mapUpdatedOpportunity.put(opp.Id,opp);
 }

  //Update contacts
  List<Contact>  Contacts = 
                    [SELECT Id, Contact__c 
                          FROM Contact 
                               WHERE OpportunityId IN :OpportunityIds];
  for(Contact con : lstContacts)
  {
    acc = mapUpdatedAccount.get(con.AccountId);
    con.Contact__c = opp.Account__c;
  }
    update Contacts;
  }

closed as unclear what you're asking by David Reed, Jayant Das, Pranay Jaiswal, battery.cord, Raul Dec 12 '18 at 10:09

Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • 3
    Are you having trouble with something? What have you tried so far? – John Towers Dec 11 '18 at 12:45
  • yes for the description and for right approch, thankyou – shanmukh Dec 11 '18 at 12:48
  • 4
    @shanmukh Could you take a few minutes to read through How to Ask and come back to edit your question? Please make sure you have a detailed, specific statement of your problem, including any errors verbatim. Right now, we only see the requirement that someone provided to you. – David Reed Dec 11 '18 at 12:55
  • As I mentioned in a commend, that has been deleted? ... This operation is quite tricky because you could be updating thousand of records here. It is advisable to move to asynchronous procedures to make sure you stay away from governor limits. Batchable APEX will be a good solution. There are questions about the full requirements. Is this a real life situation? What is the logic behind having the description updated in Opportunities and Contacts records? The business logic for this is a bit strange, can you explain a bit more the business use of this? – Carlos Naranjo Dec 11 '18 at 13:21
0

I agree with all the comments above and things you need to consider if you were solving this via code. Code provided by Carlos is very comprehensive and should work. If there is no specific reason to do this via code then Process Builder would be more simpler and straight forward solution.

enter image description here

  • Process Builder bulkification may give some problems on this kind of scenarios. If you are setting up a operation on a trigger for accounts after update, you better make sure you have control over all apex transactions happening on that trigger context or governor limits will be easily reached. – Carlos Naranjo Dec 11 '18 at 16:11
2

Account does not have any lookup to Opportunity or contact, but, oppositely, Contact and Opportunity does have an AccountId field so your trigger should look like the following way:

trigger AccountTrigger on Account (after update) {
    // Retrieve related records.
    List<Opportunity> opportunityList = [SELECT id, description FROM Opportunity WHERE AccountId IN :Trigger.newMap.keySet()];
    List<Contact> contactList = [SELECT id, description FROM Contact WHERE AccountId IN :Trigger.newMap.keySet()];    

    // Update description field.
    for(Opportunity o: opportunityList)
        o.Description = 'Opportunity Updated.';

    for(Contact c: contactList)
        c.Description = 'Description Updated.';

    // Update Lists if is there any entry.
    if(!opportunityList.isEmpty())
        Database.update(opportunityList, false);

    if(!contactList.isEmpty())
        Database.update(contactList, false);
}

Please, don't forget to use a trigger architecture for better code maintenance.

1

I think that you need to break things down in a way that you can make sure that there is not issues with SFDC Governor Limits here. You can write a trigger for accounts on update to send trigger.new to a class that will then split the updates into two batch classes, one for Contacts and one for Opportunities. You could explore getSObjectType() to simplify things a bit...

So let's say you have this trigger:

tigger AccountConOppDescUpdate on Account(after update){

   ManagingAccountConOppUpdates.HandleRelatedUpdates(trigger.new); 
}

We are only looking the new list of those accounts that were update. We send these accounts to the class ManagingAccountConOppUpdates and to the method; HandleRelatedUpdates. As mentioned, we just passing trigger.new.

This is the class body:

public class ManagingAccountConOppUpdates {

public static void HandleRelatedUpdates(list<Account> newList)
{

List<Id> contactsToUpdate = new List<Id>(); 
List<Id> opportunitiesToUpdate = new List<Id>();      

List<Account> accList = [SELECT Id, 
                          (SELECT Id, Description FROM Opportunities),
                            (SELECT Id, Description FROM Contacts) 
                               FROM Account WHERE Id In: newList];    

for(Account act: accList)
{
  for(Contact con: act.Contacts)
  {
    if(con.Description ==null)
      contactsToUpdate.add(con.Id); 
  }
   for(Opportunity opp: act.Opportunities)
   {
     if(opp.Description ==null)
      opportunitiesToUpdate.add(opp.Id);   
   }
}

    Set<Id> contactSet = new Set<Id>(contactsToUpdate); 
    Set<Id> opportunitySet = new Set<Id>(opportunitiesToUpdate);     

    // Passing contacts to batch processing       
    ContactBatch batchClassCon = new ContactBatch(contactSet);
    Database.executeBatch(batchClassCon, (Test.isRunningTest())?2000: 200);

    // Passing opportunities to batch processing
    OpportunityBatch batchClassOpp = new OpportunityBatch(opportunitySet);
    Database.executeBatch(batchClassOpp, (Test.isRunningTest())?2000: 200);

    }

}

On the code above we split our operation in two batches. You could simplify this by entering the same value for both objects. So, Contact Updated and Opportunity Update to Record Updated for both objects. This way you can execute all in one batch. But for this example we are splitting them. You can also use getSObjectType() as I mentioned before in one batch class to make it a bit more simple.

So the batch class ContactBatch and OpportunityBatch are built like this:

ContactBatch:

public without sharing class ContactBatch implements 
database.Batchable<SObject> {
    public Set<ID> contactsIds;

    public ContactBatch(Set<ID> ids)
    {
        contactsIds = ids;
    }

    public ContactBatch()
    {
        contactsIds = null;
    }

    public Database.QueryLocator Start(Database.BatchableContext bc)
    {
        String queryString = 'Select ID, Description from Contact';
        if(contactsIds!=null) queryString+= ' where ID in :contactsIds';
        return Database.getQueryLocator(queryString);
    }

    public void Execute(Database.BatchableContext bc, List<Contact> scope)
    {
        List<Contact> contactsToUpdate = new List<Contact>();

        for(Contact ct: scope)
        {
            if(ct.Description == null) {
                ct.Description = 'Contact Updated';
                contactsToUpdate.add(ct);
            }
        }
        update contactsToUpdate;
    }

    public void Finish(Database.BatchableContext bc)
    {

    }

}

For the Opportunity batch OpportunityBatch we do something similar.

OpportunityBatch:

public without sharing class OpportunityBatch implements 
   database.Batchable<SObject>{
    public Set<ID> opportunitiesIds;

    public OpportunityBatch(Set<ID> ids)
    {
        opportunitiesIds = ids;
    }

    public OpportunityBatch()
    {
        opportunitiesIds = null;
    }

    public Database.QueryLocator Start(Database.BatchableContext bc)
    {
        String queryString = 'Select ID, Description from Opportunity ';
        if(opportunitiesIds!=null) queryString+= ' where ID in :opportunitiesIds';
        return Database.getQueryLocator(queryString);
    }

    public void Execute(Database.BatchableContext bc, List<Opportunity> scope)
    {
        List<Opportunity> opportunitiesToUpdate = new List<Opportunity>();

        for(Opportunity op: scope)
        {
            if(op.Description == null) {
                op.Description = 'Opportunity Updated';
                opportunitiesToUpdate.add(op);
            }
        }
        update opportunitiesToUpdate;
    }

    public void Finish(Database.BatchableContext bc)
    {

    }

}

Give it a try, I didn't tested... but something like this will be a good approach. The all point here is to make sure that you don't get cut in a transaction that can affect probably thousand of records. Other thing to consider is if you want to update the Description field that already contains some values. We looked into that by checking if there are values inserted in the Description field. This is also good to avoid, updating records that don't need to be update.

****** UPDATE *****

I know that other answer was selected for this question but I tested this anyway and it works :) .. in case someone comes here and wants to use this solution.

After some typo corrections:

enter image description here

enter image description here

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