9

It is quite possible, and in fact recommended (if you need trigger logic on both events). See also: Trigger Frameworks and Apex Trigger Best Practices Triggers (Apex Developer Guide) A common pattern is to have three separate layers of code: the trigger itself, a handler, and a service layer. Here's the trigger framework I prefer. Trigger trigger ...


9

== is for equality checks, = is for assignment. As such: If (soAccount.ISLock__c = True){ will assign the value of true to IsLock__c, and this statement will always be true. For this reason, I always recommend that you avoid comparing to true/false values, because it can prevent typos like this from compiling. If (soAccount.IsLock__c){


6

This is a Known Issue that should be fixed in Spring '19. Until then, consider using a List<String> instead (as mentioned in the workaround), or use a Set<Id> instead, which should be more reliable. The reason why it happens is usually because of different log levels depending on how you run the test/deploy. For example, a change set would ...


6

AFAIK there is no way to do this without adding explicit logic. And that explicit logic is pretty ugly e.g. make the WF and PB set database data or static variables that signal they have run and then have the trigger check those. Which couples the pieces together horribly. If possible, write the trigger so it is idempotent i.e. nothing bad happens even if ...


6

Conceivably what you could do is set up a Queueable class. On the first pass through the trigger, instantiate and enqueue it, and then save that in a static variable so you know it's already been created. It will run once after all executions are done, in a separate transaction. The trouble is, once you have enqueued it, you can no longer alter any data you'...


5

You should filter only records that can be matched. You will get some extra results with the below approach, but hopefully fewer than 50k. Also note that NOT IN filters will give you selectivity problems if your table goes over 100k records total. Set<String> emails = new Set <String>(); Set<String> emails = new Set <String>(); // ...


5

In Apex Code, we use == for comparison, while = is for assignment. This means that you're actually trying to assign a value (true) to a field (acc.Use_School_Contacts__c). The system allows this syntax because you can perform an assignment and then use the result of that assignment later. However, in after insert and after update triggers, Trigger.new is ...


5

For the first one, instead of: affectedCasesByContactId.keyset().containsKey(...) use either the Map method containsKey on the Map: affectedCasesByContactId.containsKey(...) or the Set method contains on the Set: affectedCasesByContactId.keyset().contains(...) For the second one instead of trying to access from the List: trigger.new.get(...) access ...


5

It sounds like you are looking for an exit event. If doesn't exist yet, but you can vote for the idea, the description of which is pasted below: Since triggers only handle 200 records at a time, it would be convenient if we could schedule some code that runs in the same transaction as the current transaction, but after all other triggers, recursion, etc ...


5

If I understand your question correctly, then you actually can take your related record update logic and put it in either a before or after trigger. Salesforce's suggestion is that before triggers should be used to update data on the records taking part in the trigger (the ones stored in trigger context variables), but it's just that... a suggestion. ...


4

Credit for aggregate result trick of aliasing the field to Id goes to sfdcfox I believe this can all be reduce to: Trigger Sum on Contact(after insert, after update, after delete, after undelete){ Map<Id, Account> accountMap = new Map<Id, Account>(); for (Contact c : trigger.new == null ? trigger.old : trigger.new) ...


4

You have one constructor for after insert, after update, after delete actions. But Trigger.old is only available in update and delete triggers. That is why it fails on after insert with null pointer exception. Refer to documentation


4

What can I do here? Is there a way to run all this logic post-commit? You do need to do at least some of this asynchronously, because any other technique is going to end up in deadlock or missing records. In both triggers, build a list of unique identifiers, then pass it in to a Queueable: public class ResolveExternals implements Queueable { String[] ...


4

Trigger.new is a type of List<sObject> outside of a trigger context. You need to "cast" it back in to a List<Opportunity> for it to work: for(Opportunity oppt : (List<Opportunity>)Trigger.new) In addition, Trigger.oldMap is also a Map<Id, sObject> outside of a trigger context. You would have to cast the sobject in to an opportunity ...


4

This error has to do with the trigger context, not with the literal location of the query in the source code. It looks like your query is located within a trigger handler, meaning it's executed after being called from the trigger and therefore is running in trigger context. So let's look at this query. SELECT id, Vmstar_Id__c, GSS_Duplicate_Case__c, ...


4

This is because you are using an aggregate query on Contact: for (AggregateResult ar: [Select Count(Id) ContactCount, AccountId from Contact where AccountId IN: AccountIds GROUP BY AccountId]) Once the final Contact is deleted, there's nothing to aggregate, so you will not see an AggregateResult with that Contact's AccountId and ...


3

in spite of checking the old value by iterating the loop you can check this by using Trigger.oldMap and Trigger.newMap, use the below snippet : trigger pipelineRepContactUpdate on Account (after update) { Set<Id> lst_acc_id = new Set<Id>();//Store the sets of Impacted Account for which you have changed the field value Map<Id,Id> ...


3

Problem is that for Map<Id, Set<String>> for every new Id, value (which is Set should be initialised separately, before records are added into it. For example: Map<Id,String> Uterr = new Map<Id,String>(); List<Territory> terr = [SELECT Name, Id FROM Territory]; for(Userterritory ut : [SELECT UserId, Territoryid ...


3

If you want to update fields on trigger records, you should use before events. From the Apex Developer Guide on Triggers: There are two types of triggers: Before triggers are used to update or validate record values before they’re saved to the database. After triggers are used to access field values that are set by the system (such as a record's ...


3

Above code seems to be fine, but you need to add Test.startTest & Test.stopTest in testmethod before system.runAs. And you can also use testMethod instead of @isTest annotation for method definition. For e.g. static testMethod void unitTest() { Opportunity opp = new Opportunity(); opp.Name = 'Testing1'; opp.CloseDate = Date.today() + 30; ...


3

Answering your questions only:- Did i incorrectly state my SOQL query? Yes, SOQL in for-loop is highly not recommended. What if the for loop cross 100 records. You will get SOQL 101. So first improvement in the code would be the take out all queries from for loop. Did i incorrectly Loop the contacts? There is no bulkification. You must query all ...


3

One way to achieve this is using a static variable. In your Util or other similar class, define a static variable called inOrderTrigger. public static inOrderTrigger = false; Then in your order trigger, set it to be true. Then in your orderitem trigger, you can check the value of that static variable.


3

This error appears when you try to create an Apex Class with an Apex Trigger code. Those two metadata types are syntax-similar, but they are totally different. Check if you are trying to save this trigger as .apxc in your developer console. If so, then that's your issue. You should save an .apxt instead. Example: The file on the left is a class, and the ...


3

Try this ;) Problem in this line WR1.Report_Date__c=o.Start_Date_of_Week__c; Here WR1 is a list of Staff_work_records__c so you can directly update a property of it's element. Maybe something like this: trigger CreateWorkRecordsX on Staff_Week_Plan_Creator__c (after insert) { List <Staff_work_records__c> WR1 = new List <...


3

You need to query back for any updates. Test.startTest(); // do some stuff Test.stopTest(); Child__c updatedChild = [SELECT UpdatedField__c FROM Child__c WHERE Id = :childId]; system.assertEquals(updatedValue, updateChild.UpdatedField__c, 'Meaningful assertion');


3

You can't realistically trigger an update during an update (before or after, doesn't matter, you'll get a recursive update error), and DMLOptions won't affect the current transaction. You will necessarily need to use the @future method (or Queueable, if you desire) in order to run the assignment rules. Note that under light system load, your @future method ...


3

Best to have null guards on both parts of expressions like this: acc.Rollup_Amount_X__c += con.Amount_X__c; acc.Rollup_Amount_Y__c += con.Amount_Y__c; and one way to do that is to create a separate class that does null-guarded arithmetic: acc.Rollup_Amount_X__c = GuardedMath.add(acc.Rollup_Amount_X__c, con.Amount_X__c); acc.Rollup_Amount_Y__c = ...


3

Related fields in trigger context are null unless queried explicitly. Your options are to either: Query your users based on the values from OwnerId Create a formula field Owner_Name__c, which returns the text of Owner.Name, allowing to you use the formula in your trigger. I usually prefer a formula over the query, since its cheaper, and you can re-use it ...


3

Here's what I would suggest as a general solution to your problem. Create set of Ids for Rc.Contactpersoon__c. set<Id>rdContacts = new set<Id>; for(Relatie__c rc : rcs) { rcContacts.add(rc.Contactpersoon__c); } Then, your contact query can be done outside of the for(Relatie__c rc : rcs) { loop as something like: List<Contact> ...


3

The general rule of thumb is that if you can't have duplicates, don't use a Set. The correct form in your case would be to use a List, instead: list<Id> customObjIds = new list<Id>(); for(customObj c: trigger.new){ if(c.recordtypeId == 'x' && ((StatusOldValue != StatusNewValue) && Status ='Submitted'){ customObjIds.add(c.ID);}//...


Only top voted, non community-wiki answers of a minimum length are eligible