+ Start a Discussion
DMelsh1DMelsh1 

Need help fixing an error in trigger

Hey everyone,

I am trying to create a trigger to pull a Contacts Owner's Email and put it into an icontacts object. This is what I have but its erroring out on the second line (expecting a semi-colon, found 'OwnerIds').


trigger iContactEmailAlert on iContactforSF__iContact_Message_Statistic__c ( Before Insert, Before Update ) {

Set OwnerIds = New Set();

For ( iContactforSF__iContact_Message_Statistic__c a : Trigger.New)
{
//Adding the Owner's ids into a set
OwnerIds.Add ( a.Contact.OwnerID) ;
}

//Getting related contact owner's email address
Map conOwnerEmail = New Map( [Select Email From User Where ID IN:OwnerIds ] );

For ( iContactforSF__iContact_Message_Statistic__c a : Trigger.New)
{
//Populating the related contact's email address using Map functionality
a.ContactOwnerEmail__c = conOwnerEmail.get(a.Contact.OwnerID).Email ;
}
}   
   
I also need a test code after this. I still fairly new to coding.

Thanks for the help.
Dan
Best Answer chosen by DMelsh1
Eli Flores, SFDC DevEli Flores, SFDC Dev
Well remember our end goal is to get something like this to work.

a.ContactOwnerEmail__c = conOwnerEmail.get(a.iContactforSF__Contact__c.Owner.ContactId).Email;

So we need something were we can pass a.iContactforSF__Contact__c and end up with the related .Owner.ContactId

so in the .Owner.ContactId loop, we need to maintain the association with the a.iContactforSF__Contact__c. To do that we need to throw a map in there,

map<id, id> contactToOwneIDMap = new map<id,id>();
For ( Contact cont : [Select ID, owner.ContactID, Email from Contact where ID in :contactIDs])
{
    //Adding the Owner's ID from contact into a set
    OwnerIds.add(cont.Owner.ContactID);
    contactToOwnerIDMap.put(cont.id, cont.owner.contactID);
}

Then we change our end goal  so we can line everything up

a.ContactOwnerEmail__c = conOwnerEmail.get(contactToOwnerIDMap.get(a.iContactforSF__Contact__c)).Email;

Though really, we could simplify it by just getting the email as well in the contact query

map<id, string> contactToOwnerEmailMap = new map<id,string>();
For ( Contact cont : [Select ID, owner.ContactID, owner.Contact.Email from Contact where ID in :contactIDs])//when possible don't assign a separate variable to store the query then iterate through it. Putting the query directly into the loop saves you heap space so you are less likely to run into the memory governor limits.  
{
    //create a contactMap with the Owner 's email in it
    contactToOwnerIDMap.put(cont.id, cont.owner.Contact.Email);
}
...
//cut out the other query since it's no longer needed
...
a.ContactOwnerEmail__c =contactToOwnerEmailMap.get(a.iContactforSF__Contact__c);

Though in reality, now that i think about it a bit more, chances are you don't need this code at all and could just turn  ContactOwnerEmail__c into a formula field that does it.

All Answers

Eli Flores, SFDC DevEli Flores, SFDC Dev
you're missing the type declaration for the set

set<id> OwnerIds  = new set<id>();// =)
Eli Flores, SFDC DevEli Flores, SFDC Dev
also
Map<id, User> conOwnerEmail = new Map<id, User>([Select Email From User Where ID IN:OwnerIds ]);
DMelsh1DMelsh1
OK got it to work. Here is the trigger. Now I need help writing the test code.


trigger iContactEmailAlert on iContactforSF__iContact_Message_Statistic__c ( Before Insert, Before Update ) {


set<id> OwnerIds  = new set<id>();

For ( iContactforSF__iContact_Message_Statistic__c a : Trigger.New)
{
//Adding the Owner's ids into a set
OwnerIds.Add ( a.iContactforSF__Contact__r.Owner.ContactId) ;
}

//Getting related contact owner's email address
Map<id, User> conOwnerEmail = new Map<id, User>([Select Email From User Where ID IN:OwnerIds ]);

For ( iContactforSF__iContact_Message_Statistic__c a : Trigger.New)
{
//Populating the related contact's email address using Map functionality
a.ContactOwnerEmail__c = conOwnerEmail.get(a.iContactforSF__Contact__r.Owner.ContactId).Email ;
}
}

Thanks for the help so for.

Dan
Eli Flores, SFDC DevEli Flores, SFDC Dev
Well the trigger  probably ins't going to work as expected.

OwnerIds.Add ( a.iContactforSF__Contact__r.Owner.ContactId) ;

Trigger.New doesn't give you related objects... in this case the stuff hanging off a.iContactforSF__Contact__c. I think if you run it you'll see that OwnderIds.isEmpty()==true

You'll have to do a separate soql.

set<ID> contactIDs;

For ( iContactforSF__iContact_Message_Statistic__c a : Trigger.New)
{
//Adding the Owner's ids into a set
contactIDs.Add ( a.iContactforSF__Contact__c) ;
}

for ( Contact cont : [Select ID, owner.ContactID from Contact where ID in :contactIDs])[
    OwnerIds.add(cont.Owner.ContactID);
}

You'll also have to add a map to map a.iContactforSF__Contact__c -> cont.Owner.ContactID in there so you can match them up again.

As for testing, it's hard to say without knowing your data model.

You'll have to manually create all the related records in accordance with the data model you have  (a contact and a user at minimum) and then verify this trigger does what you want it to do. There's a great article here that should point you in the right direction:

https://developer.salesforce.com/page/An_Introduction_to_Apex_Code_Test_Methods
DMelsh1DMelsh1
Could you explain this a little more I'm confused.

"You'll also have to add a map to map a.iContactforSF__Contact__c -> cont.Owner.ContactID in there so you can match them up again."


trigger iContactEmailAlert on iContactforSF__iContact_Message_Statistic__c ( Before Insert, Before Update ) {


set<id> OwnerIds;

set<ID> contactIDs;

For ( iContactforSF__iContact_Message_Statistic__c a : Trigger.New)
{
    //Adding the contact into a set
    contactIDs.Add ( a.iContactforSF__Contact__c) ;
}

For ( Contact cont : [Select ID, owner.ContactID from Contact where ID in :contactIDs])
{
    //Adding the Owner's ID from contact into a set
    OwnerIds.add(cont.Owner.ContactID);
}


//Getting related contact owner's email address
Map<id, User> conOwnerEmail = new Map<id, User>([Select Email From User Where ID IN:OwnerIds ]);

For ( iContactforSF__iContact_Message_Statistic__c a : Trigger.New)
{
//Populating the related contact's email address using Map functionality
a.ContactOwnerEmail__c = conOwnerEmail.get(a.iContactforSF__Contact__c.Owner.ContactId).Email ;
}
}

I think I'll be able to put a test code together with that link. Thanks for that.
Eli Flores, SFDC DevEli Flores, SFDC Dev
Well remember our end goal is to get something like this to work.

a.ContactOwnerEmail__c = conOwnerEmail.get(a.iContactforSF__Contact__c.Owner.ContactId).Email;

So we need something were we can pass a.iContactforSF__Contact__c and end up with the related .Owner.ContactId

so in the .Owner.ContactId loop, we need to maintain the association with the a.iContactforSF__Contact__c. To do that we need to throw a map in there,

map<id, id> contactToOwneIDMap = new map<id,id>();
For ( Contact cont : [Select ID, owner.ContactID, Email from Contact where ID in :contactIDs])
{
    //Adding the Owner's ID from contact into a set
    OwnerIds.add(cont.Owner.ContactID);
    contactToOwnerIDMap.put(cont.id, cont.owner.contactID);
}

Then we change our end goal  so we can line everything up

a.ContactOwnerEmail__c = conOwnerEmail.get(contactToOwnerIDMap.get(a.iContactforSF__Contact__c)).Email;

Though really, we could simplify it by just getting the email as well in the contact query

map<id, string> contactToOwnerEmailMap = new map<id,string>();
For ( Contact cont : [Select ID, owner.ContactID, owner.Contact.Email from Contact where ID in :contactIDs])//when possible don't assign a separate variable to store the query then iterate through it. Putting the query directly into the loop saves you heap space so you are less likely to run into the memory governor limits.  
{
    //create a contactMap with the Owner 's email in it
    contactToOwnerIDMap.put(cont.id, cont.owner.Contact.Email);
}
...
//cut out the other query since it's no longer needed
...
a.ContactOwnerEmail__c =contactToOwnerEmailMap.get(a.iContactforSF__Contact__c);

Though in reality, now that i think about it a bit more, chances are you don't need this code at all and could just turn  ContactOwnerEmail__c into a formula field that does it.
This was selected as the best answer
DMelsh1DMelsh1
Thanks you Eli. After some backdoor work we were able to get a formula field to work. Something salesforce support said could not be done.