+ Start a Discussion
aspicciatiaspicciati 

Stuck writing a basic trigger to update ownership of a record with a look-up field...

Really easy problem (I hope!).  This is my first real trigger/class that I'm writing from scratch, so please bear with the n00b-iness :)

 

Here is what I want the code to do:

I have created a lookup relationship on case object to opportunity.  On the opportunity, I have a custom lookup to a user, called ImpUser.  When a case is created by a user from the opportunity page (via a custom button), I want it to be automatically assigned to whoever is being referenced in ImpUser.  That's it!

 

Here is my code:

 

Trigger:

trigger CaseTrigger on Case (before insert, before update) {
if(trigger.isInsert){
//creates list of cases that activated trigger called "cases"
case[] cases = Trigger.new;
//calls CaseClass Class and ReassignCase method, passing in the list
CaseClass.ReassignCase (cases);
} else return;
}

 

Class:

public with sharing class CaseClass {

public static void ReassignCase (case [] cases) {
List<case> newCases = [SELECT Id, Opportunity__r.ImpUser__r.Id, Opportunity__r.ImpUser__c FROM Case];

for(Case c :cases) {
if (c.Opportunity__r.ImpUser__c != null) {
c.OwnerId = c.Opportunity__r.ImpUser__c;
c.Subject = 'Found';
}
else c.Subject = 'Not Found';
}
}

}

 

Error:


When I create a case, it is giving me an error saying that I cannot assign a null value to the owner.  This is why I put in the if statement, and now it is just changing the subject to "Not Found" for all of the cases.  This leads me to believe the problem is with how I defining the owner, and thus the list...?  Because when I hardcode a User Id instead of the variable, it will assign the case correctly.  I honestly think that I just don't understand how to use the list...

 

Any help would be greatly appreciated!  Thanks in advance.

Best Answer chosen by Admin (Salesforce Developers) 
sfdcfoxsfdcfox

Three problems:

 

1) You're querying the entire database.

2) You didn't actually reference newCases, so it happens that you're actually referencing Trigger.new[x].Opportunity__r.ImpUser__r.Id, which IS null, because it is in a related object, and triggers do not automatically load this data.

3) You can't query the cases in a before insert trigger, because they are not yet committed to the transaction or database.

 

Instead, you need the standard "aggregate-query-update" method that is commonly used for your type of objective. It works like this:

 

trigger updateowner on case (before insert, before update) {
  // map of opportunities
  map<id,opportunity> opps = new map<id,opportunity>();
  // obtain opportunity ids
  for(case c:trigger.new) {
    opps.put(c.opportunity__c,null);
  }
  // don't include null id
  opps.remove(null);
  // query all opps and place in map
  opps.putAll([select id,impuser__c from opportunity where id in :opps.keyset()]);
  // assign owner for each non-null value
  for(case c:trigger.new) {
    if(opps.containskey(c.opportunity__c) && opps.get(c.opportunity__c).impuser__c != null) {
      c.ownerid = opps.get(c.opportunity__c).impuser__c;
    }
  }
}

Enjoy!

All Answers

sfdcfoxsfdcfox

Three problems:

 

1) You're querying the entire database.

2) You didn't actually reference newCases, so it happens that you're actually referencing Trigger.new[x].Opportunity__r.ImpUser__r.Id, which IS null, because it is in a related object, and triggers do not automatically load this data.

3) You can't query the cases in a before insert trigger, because they are not yet committed to the transaction or database.

 

Instead, you need the standard "aggregate-query-update" method that is commonly used for your type of objective. It works like this:

 

trigger updateowner on case (before insert, before update) {
  // map of opportunities
  map<id,opportunity> opps = new map<id,opportunity>();
  // obtain opportunity ids
  for(case c:trigger.new) {
    opps.put(c.opportunity__c,null);
  }
  // don't include null id
  opps.remove(null);
  // query all opps and place in map
  opps.putAll([select id,impuser__c from opportunity where id in :opps.keyset()]);
  // assign owner for each non-null value
  for(case c:trigger.new) {
    if(opps.containskey(c.opportunity__c) && opps.get(c.opportunity__c).impuser__c != null) {
      c.ownerid = opps.get(c.opportunity__c).impuser__c;
    }
  }
}

Enjoy!

This was selected as the best answer
aspicciatiaspicciati

This is perfect!  Thanks so much for the help - I actually understand it now :)  I appreciate your laying it out so cleanly and ESPECIALLY for showing me the code to use.  I'm going to try and refactor this now to change the owner of the tasks created via workflow - hopefully should be very straightforward after this explanation.

 

Thanks again!

aspicciatiaspicciati

Not sure if this is proper etiquette in the forums, but I have a continuation on the previous problem that I think should be a quick fix.  Any help in explaining would be great.

 

I am trying to do the same as above, except to have any tasks (autocreated via workflow on a new case) also reassigned.  I am getting a "Save error: Invalid foreign key relationship: Task.WhatId" error on line 9.  Is this because of a similar problem that sfdcfox described in #2 above, whereas the value doesn't exist yet in a trigger?  If so, how do I get the value populated so that I can reference against it?  Or does the "WhatId" field work differently than a regular reference field?

 

Thanks so much!!  And also, for next time, should this be a new thread or addition to the existing like I'm doing now? I just wanted to be sure sfdcfox was able to see, since you helped me with the first one :)

 

 

public with sharing class TaskClass {

	public static void updateTaskOwner (List<Task> tasks) {
	
    	  // map of opportunities
 			map<id,opportunity> opps = new map<id,opportunity>();
  			// obtain opportunity ids
  			for(Task t:tasks) {
    			opps.put(t.WhatId.opportunity__c,null);
  			}
  			// don't include null id
  			opps.remove(null);
  			// query all opps and place in map
  			opps.putAll([select id,impuser__c from opportunity where id in :opps.keyset()]);
  			// assign owner for each non-null value
  			for(Task t:tasks) {
    			if(opps.containskey(t.WhatId.opportunity__c) && opps.get(t.WhatId.opportunity__c).impuser__c != null) {
      				t.ownerid = opps.get(t.WhatId.opportunity__c).impuser__c;
    			}
  			}
	}
}