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
Kyle_at_boxKyle_at_box 

Writing a query for master-detail relationship in a trigger

Hi All,

 

I'm working with a couple of custom objects that have a master-detail relationship with one another.  The master's api name is zqu_Quote__c and the detail's api name is zqu__QuoteCharge__c.

 

I'm trying to write a simple trigger that will query for the field "zqu__Discount__c" in the detail object and assign that value to the field Discount__c in the master object.  Unfortunately, I'm having trouble accessing the master object in my query.  My code is below - I think my issue has to do with the syntax I'm using to call for the ID of the zqu__Quote__c object.  Any suggestions?

 

 

trigger DiscountUpdate on zqu__QuoteCharge__c (after insert) {

	 list<QuoteCharges__c> myList = [select q.Id,    q.zqu__Discount__c, q.zqu__Quote__r.Discount__c from zqu__QuoteCharge__c q where q.Quote__c =:quoteID];
	 
	 for (QuoteCharge__c qc: myList) {
	 	qc.zqu__Quote__r.Discount__c = qc.zqu__Discount__c;
	 	}
	 update mylist;
}

 

 

Best Answer chosen by Admin (Salesforce Developers) 
mariagusmariagus

You get this error because you haven't defined the "quoteID" yet.

 

I suppouse this is the Id of your header object.

Why don't you try with my second aproach? I think it is much more completed, and it works. I did something similar yesterday.

 

I this case you will fill a set with the header objects, then you can create your query and use

"q.Quote__c in :quoteIDSet"

 

and after that assign the ne value, add to the new list and finally, update the header object.

 

Let me know if you have any other problem.

 

All Answers

mariagusmariagus

Hi,

 

Try to create a new list where you can add the object hat you have just modified.

After that, update this new list.

 

Something like:

List<QuoteCharge__c> newList = new List<QuoteCharge>();

for(QuoteCharge__c qc: mylist)

{

    qc.discount = zqu_Discount;

    newList.add(qc);

}

update newList;

 

 

If this doesn't work, you try:

 

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

for(DetailObject__c iter : trigger.new)

     headerObjectIdSet.add(iter.HeaderId);

 

List<HeaderObject> headerToUpdate = new List<HeaderObject>();

List<HeaderObject> headerList = [Select Discount from HeaderObject where Id in :headerObjectIdSet];

if(headerList != null)

{

    for(HeaderObject header : headerList)

    {

        header.Discount = value;

        headerToUpdate.add(header);

    }

    update header;

}

 

Kyle_at_boxKyle_at_box

Hi Mariagus,

 

Thanks for the reply!  I've added the changes you suggested in the first half like this:

 

 

trigger DiscountUpdate on zqu__QuoteCharge__c (after insert) {
	list<zqu__QuoteCharge__c> newList = new list<zqu__QuoteCharge__c>();
	list<QuoteCharges__c> myList = [select q.Id,  q.zqu__Discount__c, q.zqu__Quote__r.Discount__c from zqu__QuoteCharge__c q where q.Quote__c =:quoteID];
	 
	for (QuoteCharge__c qc: myList) {
	 	qc.zqu__Quote__r.Discount__c = qc.zqu__Discount__c;
	 	newList.add(qc);
	 	}
	 	update newList;
}

 (It was returning an invalid type error if i tried to make the list of type <QuoteCharge>, but i think this will work).  I'm still returning an error for the final statement in my query, where I ask:  where q.Quote__c =: quoteID.  It's telling me it doesn't recognize the variable quoteID.  Am I missing something syntactically here?  

 

Thank you so much!  I appreciate the help.

 

mariagusmariagus

You get this error because you haven't defined the "quoteID" yet.

 

I suppouse this is the Id of your header object.

Why don't you try with my second aproach? I think it is much more completed, and it works. I did something similar yesterday.

 

I this case you will fill a set with the header objects, then you can create your query and use

"q.Quote__c in :quoteIDSet"

 

and after that assign the ne value, add to the new list and finally, update the header object.

 

Let me know if you have any other problem.

 

This was selected as the best answer
Kyle_at_boxKyle_at_box

Looks like it's working now - or at least, the only error it's returning now is that i have 0% coverage for the trigger.  I just need to write a unit test for this bugger, then I'll be able to deploy.  Thank you so much for all the help!!! (and if you have a sample unit test you used for the trigger you built yesterday, I'm sure wayward google searchers who stumble upon this thread months from now would love to see it :) )

 

once i get this to successfully deploy, can i mail you a beer or something?

 

here's what I have now:

 

 

trigger DiscountUpdate on zqu__QuoteCharge__c (after insert) {
	set<ID>idSet = new Set<ID>();
	for(zqu__QuoteCharge__c zq : trigger.new){
		idSet.add(zq.ID);
	}
	list<zqu__QuoteCharge__c> quoteToUpdate = new list<zqu__QuoteCharge__c>();
	list<zqu__QuoteCharge__c> myList = [select q.Id, q.zqu__Discount__c, q.zqu__Quote__r.Discount__c from zqu__QuoteCharge__c q where q.zqu__Quote__c in :idSet];
	 
	for (zqu__QuoteCharge__c qc: myList) {
	 	qc.zqu__Quote__r.Discount__c = qc.zqu__Discount__c;
	 	quoteToUpdate.add(qc);
	 	}
	 	update quoteToUpdate;
}

 

 

mariagusmariagus

Hey!! You got it!!

 

We don't create a unit test just for a trigger. What we do is to create unit tests for our classes. Your trigger will be covered  if one of these test insert the obeject  (your trigger is after insert) So, if for example, you have a class where a method is to check the Discount__c value that after inserting a detial object, your test could be:

 

@isTest

private class myUnitTest

{

         private testMethod static void test()

         {

              HeaderObject myHeaderObject = new HeaderObjec();

              myHeaderObject.Name = 'myHeader';

              //fill fields with values that you need

              insert myHeaderObject;

 

              DetailObject myDetailObject = new DetailObject();

              myDetailObject.Name = 'myDetailObject';

              //Don't forget link the child with the father

              myDetailObject.HeaderObjectId = myHeaderObject.Id;

              myDetailObject.Discount__c = 5;

              //fill field with values that you need

              insert myDetailObject;

             

              //At this point, your trigger should be covered.

 

              //Call to the method that you want to cover on your class

              Decimal discountValue = MyClass.getMyHeaderObjectDiscountValue();

              System.assertEquals(discountValue,5);

         }

}

 

Of course, you can following calling to other methods on your class.

 

This should be enough for your test.

Kyle_at_boxKyle_at_box

yep, definitely mailing a beer.  I ended up writing one myself, and it turns out to be remarkably similar to what you've put down here.  for what it's worth:

 

 

public with sharing class DiscountUpdateTestMethod {
	// test the trigger
	static testMethod void updateTest() {
		test.startTest();
	 	
	 	// create and insert a new quote record
	 	zqu__Quote__c testQuote = new zqu__Quote__c();
	 	insert testQuote;
	 	
	 	// create and insert a new QuoteCharge record that has the newly created Quote record as its master record.
	 	// assign an arbitrary value to the QuoteCharge's discount field.
	 	zqu__QuoteCharge__c testQuoteCharge = new zqu__QuoteCharge__c(zqu__Quote__c = testQuote.ID, zqu__Discount__c = 5);
	 	insert testQuoteCharge;
	 	
	 	// go through everything that happens in the trigger
	 	set<ID>testIdSet = new Set<ID>();
	 	testIdSet.add(testQuoteCharge.ID);
	 	
	 	list<zqu__QuoteCharge__c> testQuoteChargeToUpdate = new list<zqu__QuoteCharge__c>();
	 	list<zqu__QuoteCharge__c> testQuoteChargeQuery = [select q.Id, q.zqu__Discount__c, q.zqu__Quote__r.Discount__c from zqu__QuoteCharge__c q where q.zqu__Quote__c in :testIdSet];
	 	
	 	for (zqu__QuoteCharge__c qc: testQuoteChargeQuery){
	 		qc.zqu__Quote__r.Discount__c = qc.zqu__Discount__c;
	 		testQuoteChargeToUpdate.add(qc);
	 	}
	 	
	 	update testQuoteChargeToUpdate;
	 	
	 	test.stopTest();
	 	
	 	for(zqu__QuoteCharge__c qc: testQuoteChargeToUpdate){
	 		system.assertEquals(qc.zqu__Quote__r.Discount__c, qc.zqu__Discount__c);
	 	}
	 	
	 	
	 }
}

 

 

mariagusmariagus

Good job :)