function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
RandyBarton24RandyBarton24 

SOQL Relationship Question for PricebookEntries

Hey Everyone,

I'm wondering if this is possible or if there is a better solution.  I am trying to access PricebookEntries from an Opportunity SOQL query.  Let me try to explain with an example:
Opportunity[] updatedOpps = [SELECT Id, 
		RecordTypeId,
		Number_of_Providers__c, 
		RecurSoft__Contract_Signed_Date__c, 
		RecurSoft__Contract_Term_Start_Date1__c, 
		RecurSoft__Trial_End_Date1__c, 
        Name, 
        RecurSoft__Initial_Contract_Term__c, 
        RecurSoft__Number_of_Free_Months__c,  
        RecurSoft__Trial__c, 
        HasOpportunityLineItem, 
        Number_of_SF_products__c, 
        Number_of_MSF_products__c, 
        CampaignId,
        	Campaign.Product_1_Name1__c,
	    	Campaign.Product_2_Name_2__c,
	    	Campaign.Name,
	    	Campaign.Type,
	    	Campaign.Trial_Period__c,
	    	Campaign.Free_Months__c,
	    	Campaign.Free_Months_Setting__c,
	    	Campaign.Promo_Product1__c,
	    	Campaign.Product_1_Sales_Price__c,
	    	Campaign.Product_2_Sale_Price__c, 
	    Pricebook2Id,
    		Pricebook2.Name,
    		Pricebook2.IsStandard,
    		(select Id,
	    		Product2Id,
	    		UnitPrice,
	    		ProductCode
	    		from PricebookEntries),
		(SELECT Id,
	    	Is_Promo_Item__c,
	    	ListPrice,
	    	UnitPrice,
	    	OpportunityId,
	    	PricebookEntryId,
	    	PriceBookEntry.Name,
	    	PriceBookEntry.UnitPrice,
	    	PricebookEntry.Product2Id, 
	    	PricebookEntry.Product2.Name,
	    	PricebookEntry.Pricebook2Id
	    	FROM OpportunityLineItems)
        FROM Opportunity 
        WHERE Id IN :oppIds]);
The query isn't working because there isn't a direct relationship between the Opportunity and PricebookEntry SObjects.  I can access PricebookEntries through the OpportunityLineItem SObject, but what I really am looking to access is a list of all PricebookEntries in an Opportunities current Pricebook in order to add OpportunityLineItems.  I really want to avoid looping through a separate query to get the PricebookEntries. 

I am trying to access the info in order to auto-add products to an Opportunity in the following method (the "updatedOpps" parameter is the list returned from the above SOQL query; the method is called by an After Insert trigger on the Opportunity):
public static void addStandardProducts(Opportunity[] updatedOpps) {

    	Set<String> currentOpportunityLineItems = new Set<String>();
    	Map<Id, OpportunityLineItem> mapInsertOppLis = new Map<Id, OpportunityLineItem>();

    	for(Opportunity o : updatedOpps) {

    		if(o.RecordTypeId != DEFAULT_RENEWAL_RECORD_TYPE.getRecordTypeId()){

	    		if(o.HasOpportunityLineItem) {

	    			for(OpportunityLineItem oppLi : o.OpportunityLineItems) {
	    				currentOpportunityLineItems.add(oppLi.PricebookEntry.ProductCode);
	    			}
	    		}

	    		for(PriceBookEntry pbEntry : o.Pricebook2.PricebookEntries) {

	    			if(pbEntry.ProductCode == SFProduct && !currentOpportunityLineItems.contains(SFProduct)) {
	    				OpportunityLineItem newOppLi = OpportunityUtilities.addOpportunityLineItem(o, pbEntry, 1);
	    				mapInsertOppLis.put(pbEntry.Id, newOppLi);
	    			}

	    			if(pbEntry.ProductCode == MSFProduct && !currentOpportunityLineItems.contains(MSFProduct)) {
	    				OpportunityLineItem newOppLi = OpportunityUtilities.addOpportunityLineItem(o, pbEntry, 1);
	    				mapInsertOppLis.put(pbEntry.Id, newOppLi);
	    			}

	    			if(pbEntry.ProductCode == APProduct && !currentOpportunityLineItems.contains(APProduct) && o.Number_of_Providers__c > 3) {
	    				Decimal q = o.Number_of_Providers__c - 3;
	    				OpportunityLineItem newOppLi = OpportunityUtilities.addOpportunityLineItem(o, pbEntry, q);
	    				mapInsertOppLis.put(pbEntry.Id, newOppLi);
	    			}
	    		}
	    	}
	    	insert mapInsertOppLis.values();
	    	currentOpportunityLineItems.clear();
    	}
    }
Any ideas of how this could be possible without a separate query?  Or any ideas of a better solution altogether?

Thanks in advance for your help!
 
Best Answer chosen by RandyBarton24
bob_buzzardbob_buzzard
You won't be able to do this without a separate query, as SOQL requires a relationship between sobjects in order to be able to join, and without a join you won't get back all of the records that you want.  If you are worried about the additional query affecting governor limits, its no different to using a sub-query as according to the docs at : http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_gov_limits.htm

--- snip ---

In a SOQL query with parent-child relationship sub-queries, each parent-child relationship counts as an additional query. 

--- snip ---

All Answers

bob_buzzardbob_buzzard
You won't be able to do this without a separate query, as SOQL requires a relationship between sobjects in order to be able to join, and without a join you won't get back all of the records that you want.  If you are worried about the additional query affecting governor limits, its no different to using a sub-query as according to the docs at : http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_gov_limits.htm

--- snip ---

In a SOQL query with parent-child relationship sub-queries, each parent-child relationship counts as an additional query. 

--- snip ---
This was selected as the best answer
RandyBarton24RandyBarton24
Thanks for the response.  I wasn't aware of the sub-query effect on governor limits.  Thanks for your help!