Take the 2-minute tour ×
Salesforce Stack Exchange is a question and answer site for Salesforce administrators, implementation experts, developers and anybody in-between. It's 100% free, no registration required.

For a trigger on Opportunity:

Objects are Account, Opportunity, and a Custom Object. There is one account to many opportunities and one account to many custom objects.

I need to compare values on Opportunity and Custom Object, and create a lookup from Opportunity to Custom Object if a few conditions are true. Using loops w/o any Maps I built working code but it cannot handle bulk inserts.

Is building a Map on Account the correct approach?

>  map  AcctOppCustomObjectMap = new map ([Select ID, (Select xxx From xxx__r),(Select yyy From yyy__r) From Account where Id IN :idSet]);

How do I iterate over children records? I know how to get the first values from a child record:

string strName1 = AcctOppCustomObjectMap.get(i).xxx_r[0].Name;

A couple of links I found helpful: one, two.

Thanks!

share|improve this question

2 Answers 2

up vote 4 down vote accepted

The children records will be contained within standard List collections under the parent object record.

Enhancing your much-too-genericized code sample:

Map<Id, Account> AcctOppCustomObjectMap = new Map<Id, Account>([SELECT Id
                                                                    ,(SELECT xxx 
                                                                        FROM xxx__r)
                                                                    ,(SELECT yyy 
                                                                        FROM yyy__r) 
                                                                FROM Account
                                                                WHERE Id IN :idSet]);

List<yyy__c> yThingsToUpdate = new List<yyy__c>();

for (Id accountId : AcctOppCustomObjectMap.keyset()) {
    Account acct = AcctOppCustomObjectMap.get(accountId);

    // the acct reference will have child lists for your subqueries
    // they will not be null, but they could be empty lists
    List<xxx__c> xxxList = acct.xxx__r;
    List<yyy__c> yyyList = acct.yyy__r;

    // iteration of the child records possible now using these two lists
    for (xxx__c xThing : xxxList) {
        for (yyy__c yThing : yyyList) {
            if (xThing.value == yThing.value) {
                // create your relationship and 
                // add to a list for bulk update / insert
                yThingsToUpdate.add(new yyy__c(Id = yThing.Id
                                                   , xxx__c = xThing.Id));

                break; // exit the for loop on the first match if desired
            }
        }
    }
}


if (!yThingsToUpdate.isEmpty()) {
    update yThingsToUpdate;
}

I would probably iterate each child list just once each to create maps of the contents by a desired key so that I could perform a Map.get() instead of repeatedly iterating lists to find the other child record to compare against. Your code sample needs more specific information in it.

Repeated iteration of the yyy list within the xxx list will limit your ability to process records since these will use script statements to iterate and match the records.

share|improve this answer

Thanks for the great response, despite the limited details I provided. The code is below.

In terms of your last two paragraphs, do you think iterating once and building a Map with ID, Relationship__c where the Opportunity ID is the key is the way to go?

Set<ID> AllOppIDs = new Set<ID>();

for (Opportunity a : Trigger.new) {
    OppAcctIds.add(a.accountID);
}
if (Constants.runTrigger) {

Map<ID, Account> AcctMap = New Map<ID, Account>([
                            SELECT ID, 
                                (SELECT ID, Relationship__c.account__c, Service_Type__c, Office__c 
                            FROM Relationships__r),
                                (SELECT ID, AccountID, Service_Type__c, Team_Ownership__c, Relationship__c,
                                    Relationship__r.ID, Owner.Office__c
                                FROM Opportunities)
                            FROM Account WHERE ID IN : OppAcctIDs]);

Map<ID, Opportunity> UpdateOppMap = new Map<ID, Opportunity>();

for (Id accountId : AcctMap.keyset()) {
    Account Acct = AcctMap.get(accountId);

    List<Opportunity> OppList = Acct.Opportunities;
    List<Relationship__c> RelList = Acct.Relationships__r;

    for (Opportunity Opp : OppList) {
        for (Relationship__c Rel : RelList) {
            if (RelList.size()>0) {
                if (Opp.Relationship__c == null) {
                    if (Opp.Service_Type__c == Rel.Service_Type__c && Opp.Owner.Office__c == Rel.Office__c) {
                        Opp.Relationship__c = Rel.ID;
                    }
                }
                else if (Opp.Relationship__c != null) {
                    if (Opp.Relationship__c == Rel.ID) {
                        if (Opp.Owner.Office__c != Rel.Office__c || Opp.Service_Type__c != Rel.Service_Type__c) {
                            Opp.Relationship__c = null;
                        }
                    }  
                }      
            }
        }
        UpdateOppMap.put(Opp.ID, Opp);
    }
}
Constants.runTrigger = false;

if (!UpdateOppMap.isEmpty()) {
    Update UpdateOppMap.values();
}
}

}

share|improve this answer
    
Whether or not you are building maps to store the data in the trigger is really dependent on the rest of the design of the trigger code. A basic trigger's operation may perform just fine iterating lists but a trigger with more complicated operations probably would benefit from the 'quick access' of a map value by key. Your unit tests should exercise this trigger code using large data volumes to make sure it works in your scenario. –  Mark Pond Dec 28 '12 at 2:12

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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