I am attempting to code my first trigger... without much success.
I have two objects Invoices (API NAME: InForceEW_invoice_c) and Receivables (API NAME: InForceEW_Receivable_c). Both objects are children of an account.
The invoice records are populated first and then receivables are created later (from an integration).
When a receivable record is created or updated I want a trigger to check if there is an invoice record which has the same name (some receivable records relate to a corresponding invoice and they will have the same name) and create a relationship between the two records.
*Some receivables will not have a matching invoice record - not sure if this could cause an error?
The trigger that I have written so far (based on other examples) is:
Trigger LinkReceivable on InForceEW_Receivable_c (before insert, before update) {
InForceEW_invoice_c invo = [Select Id From InForceEW_invoice_c Where Name IN:trigger.newMap.keyset()];
for(InForceEW_Receivable_c theReceivable: trigger.New){
theReceivable.Invoice__c = Invo.Id; } }
This does not work (no surprises there) and is throwing the below error:
Error Message : Upsert failed. First exception on row 0 with id a0AO0000009ku64MAA; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, LinkReceivable: execution of BeforeUpdate
caused by: System.QueryException: List has no rows for assignment to SObject
Trigger.LinkReceivable: line 3, column 1: []
Stack Trace : (InForceEW)
Any help would be most welcome!
UPDATE
I don't have the reputation yet to put an answer on my own question (for 8 hours after posting) so here's an update:
BTW: I managed to get the trigger to work using the below code (thanks to Shane for pointing me in the right direction with the Name not ID!) :
Trigger LinkReceivable on InForceEW_Receivable_c (before insert, before update) {
for(InForceEW_Receivable_c theReceivable: trigger.New){
InForceEW_invoice_c invo = [Select Id From InForceEW_invoice_c Where Name = :theReceivable.Name];
theReceivable.Invoice__c = Invo.Id;
} }
I assume that this is not "bulkified" for multiple upserts?
I'll take a look at your answer Bachovski and see what I can work with that.
BTW: How do you get the right formatting to show code in your post on here (I'm having to use block quote)?
RESOLUTION UPDATE:
It works!!!!
Finally got success and it's all down to the great answers that have been provided here.
Ultimately it was Bachovski's answer that I utilised, with a tweak to update the invoice rather than the receivable.
And the penny finally dropped that the "Update" method just needs a list of records to "update". You have to update the field beforehand and the "Update" method just pumps it through... please tell me if I've got that wrong!
Here is the final code that worked:
Trigger LinkReceivable on InForceEW__Receivable__c (after insert, after update) {
// build a set of receivable names Set <String> receivableNames = new Set <String>();
for(InForceEW__Receivable__c theReceivable : trigger.New) {
receivableNames.add(theReceivable.Name); }
// Map the invoice names and the actual invoice records based on the receivable names
Map <String, InForceEW__invoice__c> matchingInvoicesMap = new Map <String, InForceEW__invoice__c> ();
for (InForceEW__invoice__c invoice : [Select Id, Name From InForceEW__invoice__c Where Name IN :receivableNames]) {
matchingInvoicesMap.put(invoice.Name, invoice); }
List <InForceEW__invoice__c> >InvoicesToUpdate = new List <InForceEW__invoice__c> ();
// go through the records in the trigger again and check whether we have found a matching receivable and invoice
for(InForceEW__Receivable__c theReceivable : trigger.New) {
if (matchingInvoicesMap.get(theReceivable.Name) != null)
{
// we found a matching one
matchingInvoicesMap.get(theReceivable.Name) .receivable__c = theReceivable.Id;
// add it to a separate list and update it
InvoicesToUpdate.add(matchingInvoicesMap.get(theReceivable.Name));
}
}
update InvoicesToUpdate;
}