+ Start a Discussion
DTCFDTCF 

Trigger firiing in parent-child relationship inserts

Will an "onUpdate" trigger fire on a parent object when a new child record is inserted? Is there anyway to prevent that from happening? I'm getting self-reference problems when I want to insert a new record under some circumstances, but I specifically do not need or want the trigger of the parent object to fire.

 

Thanks!

Best Answer chosen by Admin (Salesforce Developers) 
DTCFDTCF

Thank you, that's actually a really good idea. I can't test it out and I can't say that it's the "Accepted Solution", but I really appreciate your feedback.

 

I eventually got this to work (so far so good in production...no news is good news!) It was extremely challenging, but it involved several steps and different approaches (after a bunch of dead ends).

 

The first was I moved a lot of code into the controller(s) that didn't absolutely have to be in the trigger(s). That helped some. Maybe it's a lesson not to use triggers any more than you have to, I don't know.

 

Then, instead of dealing with a conditional case in my code related to "old" objects/data structure in the system from the "old" version of the app, I basically wrote an upgrade routine to convert the old objects into the new format that my code would run on.

 

Then, finally, I discovered something that I actually had been missing that really was an eye opener. It is totally a bit of egg on my face because it didn't occur to me and I was ignorant of it, but I'm quite happy finally to have learned my lesson the hard way. I'm fine with that. I hadn't realized that you could traverse multiple relationship fields with SOQL!

 

So the nature of this application is that I have numerous different objects that relate to one another, several of which are junction objects. So, traversing them was a nightmare. This new found awareness didn't automatically make it easy, but it made the difference from it being impossible, to it being hard but at least possible!

 

For example, if you have an object with a lookup field to another, you can do lookup1__r.lookup2__r.lookup3__r.field__c

 

I didn't realize you could traverse two or more of the relationship lookups! Again, it's probably the type of thing that I should have known, but I'm happy just to have learned the lesson. In fact, I wasn't even using __r as much as I should have because without realizing that you could traverse multiple levels, it didn't strike me as being the underlying answer to my many of my problem(s).

 

Thanks for all of your help!

All Answers

EnthEnth

Yes it will fire an update on the parent when a child is updated but I *think* only if you have a roll up summary field on the parent. Let me know if this is the case.

 

Regardless, if you don't want the parent trigger to carry out any actions if it does fire, then you can add a trigger for the child object and use the runOnce() technique described here to ensure it doesn't cause any damage.

 

This won't of course stop any workflows or validation rules firing however.

DTCFDTCF

Thanks for the feedback. yes, I think I do have a rollup summary on the parent object. The irony is that I added the rollup summary field to avoid having to do so much processing of child objects in the parent trigger itself to avoid SOQL query limits (even after bulkifying my triggers and all that).

 

I did actually use the run-once technique at a point initially as a way to overcome the original problem I had (with the query limits). I'll re-explore it in this context, but I'm kind of confused with the scope of how a static variable would operate within the context of an existing trigger when a new trigger context is being created operating on a new object type. I'll give it a shot anyway.

 

Perhaps this is not the place, but I can't help but express some frustration with this overall issue. I've been developing on the platform for over a year so it's not like I'm a total newbie, but this couldn't be more frustrating. This is something that should have taken me less than a couple of hours under ideal conditions, and it's balooned into more than five days, seriously. My client couldn't be more frustrated because their app has been half-functional where it's more trouble to back-out of the deployment since discovering this "bug", and I've hit an extreme wall trying to solve this one issue where it seems like I've been five minutes away from solving it for over five days. I'm actually kind of embarrassed because it either makes salesforce look really bad or me look really stupid, both of which are awkward for me to explain to the client.

 

So here's an attempt to address the overall underlying issue. I don't know exactly how, but salesforce should make all attributes of "parent" objects available from the association of child lookups *by default* without having to query for the actual object from the database. Maybe it's technically not possible, but I can't help but think it wouldn't be all that hard and it would save thousands and thousands of hours of work (and untold errors) by each and every developer of the platform.

 

The issue is pretty simple. I have an object, object A that has an association (lookup or master-child...doesn't matter) to another object B.

 

I'm using object A in Apex. I see that it has a relationship to object B. I want to some attribute of object B. I should be able to say "ObjectB.Attribute" without having to query for the stupid object.  it should be transparent.

 

I (and I'm guessing just about everyone else) does this constantly, and I find myself repeating myself dozens and dozens of times, in highly error-prone ways, hitting every Apex limit imaginable. Every application I want to develop needs this.

 

Salesforce should fix this and make it a function of the language itself. This is what people do. They relate objects to other objects. They want to recall and traverse those relationships. Am I missing something?

 

A manifestation of this fundamental flaw with Apex and Force.com can be seen in how they implemented "Filtered Lookup" fields of related list with this new release (stll in beta). They made them filterable by strings only. So I hit this parent/child issue yet *again* (they didn't really solve the root cause of the problem) because the thing I wanted to filter by was the parent/child relationship to only show child objects that were related to the parent. So I needed to filter in Apex by String, then query the database for all children, look for children that had the same name as the object being looked for, then find it's actual id to use when using the object.

 

Sorry if you can't follow me. If I'm way off base and just missing something, please let me know. If you're from salesforce and you're reading this and you actually care about this issue and don't understand the underlying problem and what people "in the trenches" are trying to do and failing at, feel free to give me a call at 617 407 5149 and I'll be happy to explain.

 

It's so, so, so, so, so ugly and pathetic that Force.com and Apex make me and every other developer do this type of stuff. I mean the good news is that the platform is so powerful that I'm forced to do that in the first place, but still. They'll have to address this root cause at some point if they want to be taken seriously as a "real" platform.

 

So back to day 6 (and at least twelve hour days) of what should have been *at most* four or five hours. I'm going to send a link to this post to my client so they understand this is a salesforce issue unless I can be proven wrong.

 

I'm tired of taking the hit for what I consider to be a fundamental flaw in the force.com platform that prevents me, other developers, and by extension, salesforce customers from being successful with the application. I'm personally on the hook for the price differential of lost time and productivity in this project overrun.

 

I quoted the client two days, which should have been easily accomplished if it wasn't for the platform. So, while you're at it, salesforce, you can cut me a check for $6,600.00, which is the cost of this project overrun that I attribute solely to the flaw of your platform.

 

So pay up, or otherwise, call me an idiot, publically, and tell me what I'm doing wrong so that other people can learn from my mistakes and be more successful with your platform. Let's hear it. I'm calling you out. PAY UP!

 

--One *really* frustrated force.com developer on behalf of his pissed of customer

DTCFDTCF

I think you are right. It does fire it only if there is a rollup summary, and there is one. I tried the static variable technique, but it doesn't seem to save the "state" of the static variable between the parent object (record) and the child object (record) it's trying to insert in order to prevent it from trying to update itself. It doesn't respect the static variable reference because it seems that inserting a new record of child B causes a brand new trigger to fire in a new context (not the original). I don't get this at all. I also tried adding the runOnce in the child trigger like you suggested, but again, that's a different context than the original parent trigger and it doesn't seem to pass that off to the parent trigger.

 

http://www.salesforce.com/us/developer/docs/apexcode/index_Left.htm#StartTopic=Content%2Fapex_classes_static.htm%23using_static_methods_and_variables|SkinName=webhelp

 

"A recursive trigger might use the value of a class variable to determine when to exit the recursion."

 

The problem with that is that it's not a recursive trigger and it doesn't need only to reference itself. I have been able effectively to use the static variable, and even a static list that gets filled with records that should or shouldn't be updated based on a date between different before/after insert/update trigger "states". In this case, however, it's a trigger on an object that calls an insert of another brand new record, which I'm understanding will cause its own trigger automatically to fire up its own butt because the parent object has a rollup summary of a child's field. There doesn't seem to be any way to avoid this.

 

I even thought to create a boolean field on the child object, where upon the (automatic) firing of the parent object's trigger, it will query all instances of its children and see if they have the field, and if they do, not to cause the parent to update and basically skip all processing. The problem with that approach here is that it seems that parent trigger is firing concurrently with the insert of the child record (in the same transaction I guess), so the child record is not present in the db before it causes the automatic firing of its parent's trigger (due to the rollup summary).

 

Please see below more details about the situation. Do I have it right how the static variable needs to function?

 

Object Type A Trigger (before insert, after insert,before update,after update)

 

    -Has a rollup summary of a field from child object B

    -Needs to have a trigger that checks to see if there are no child records of Object type B. If there aren't any, it needs to insert a new one

    -Has a static variable referenced through the runOnce that will check to see if it's already been run

 

              Object Type B Trigger, child of Object A Master

                     - Needs to instantiate an instance of the runOnce variable and set it to false

 

I've been thinking of ways I could do this in classes without tying it to a trigger, but I don't think it's possible. I'll keep trying to think of a way. Again, the reason why I got to this point in the first place was that I added the rollup summary to avoid having to do any child processing.

 

Maybe I'll just create a text field and store the stuff in there, comma delimited. Keeping relationships between objects and coding around it is just way, way too painful. Is that something people do? I'm sure it's not best practices, but I'm not sure what that means anymore. :)

 

Maybe an @future call is something that can help? I keep having the feeling there's something very fundamental I'm missing in all of this. It can't possibly be this hard.

 

Sorry if my previous post was a bit over the top. I'm just frustrated after rearchitecting my approach and hitting a dead end each time I try a new strategy. I would so love to be told what I'm doing wrong.

CaptainObviousCaptainObvious

See if something like this would help...

 

Create a new field on the Parent Object:

Label: Number of Children
Data Type: Roll-up Summary
Summarized Object: Child Object
Roll-Up Type: Count

 

Now in your Parent Object Trigger:

 

trigger parentObjTrigger on Parent_Object__c (before update) {
    for(Parent_Object__c po : trigger.new){
        Double oldCount = Trigger.oldMap.get(po.id).No_of_Children__c;
        if ( po.No_of_Children__c == oldCount ) {

            ...

            //Do something here when NOT inserting/deleting a child record

            ...

        }
    }
}

 

When a child record is inserted (or deleted) the new value of the Number of Children summary field will not be equal to the old value. Therefore, although the parent rollup summary field will be updated, the code inside the trigger will not be executed (at least, that's the idea) :smileyvery-happy:

DTCFDTCF

Thank you, that's actually a really good idea. I can't test it out and I can't say that it's the "Accepted Solution", but I really appreciate your feedback.

 

I eventually got this to work (so far so good in production...no news is good news!) It was extremely challenging, but it involved several steps and different approaches (after a bunch of dead ends).

 

The first was I moved a lot of code into the controller(s) that didn't absolutely have to be in the trigger(s). That helped some. Maybe it's a lesson not to use triggers any more than you have to, I don't know.

 

Then, instead of dealing with a conditional case in my code related to "old" objects/data structure in the system from the "old" version of the app, I basically wrote an upgrade routine to convert the old objects into the new format that my code would run on.

 

Then, finally, I discovered something that I actually had been missing that really was an eye opener. It is totally a bit of egg on my face because it didn't occur to me and I was ignorant of it, but I'm quite happy finally to have learned my lesson the hard way. I'm fine with that. I hadn't realized that you could traverse multiple relationship fields with SOQL!

 

So the nature of this application is that I have numerous different objects that relate to one another, several of which are junction objects. So, traversing them was a nightmare. This new found awareness didn't automatically make it easy, but it made the difference from it being impossible, to it being hard but at least possible!

 

For example, if you have an object with a lookup field to another, you can do lookup1__r.lookup2__r.lookup3__r.field__c

 

I didn't realize you could traverse two or more of the relationship lookups! Again, it's probably the type of thing that I should have known, but I'm happy just to have learned the lesson. In fact, I wasn't even using __r as much as I should have because without realizing that you could traverse multiple levels, it didn't strike me as being the underlying answer to my many of my problem(s).

 

Thanks for all of your help!

This was selected as the best answer