You need to sign in to do that
Don't have an account?
Really stuck on trigger challenge
Hi
I'm trying to do the Understanding Execution Context module challenge and I really can't see why this won't work. The following code says
System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, AccountTrigger: execution of BeforeInsert caused by: System.SObjectException: DML statement cannot operate on trigger.new or trigger.old Class.AccountTriggerHandler.CreateAccounts:
trigger AccountTrigger on Account (before insert) {
if ( Trigger.isBefore && Trigger.isInsert)
{
AccountTriggerHandler.CreateAccounts(Trigger.new);
}
}
public class AccountTriggerHandler {
public static void CreateAccounts(List<Account> Accnts)
{
List<Account> ValidAccounts = new List<Account>();
for (Account a : Accnts) {
a.ShippingState = a.billingState;
ValidAccounts.add(a);
}
if (ValidAccounts.size() > 0) {
insert ValidAccounts;
}
}
}
I'm trying to do the Understanding Execution Context module challenge and I really can't see why this won't work. The following code says
System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, AccountTrigger: execution of BeforeInsert caused by: System.SObjectException: DML statement cannot operate on trigger.new or trigger.old Class.AccountTriggerHandler.CreateAccounts:
trigger AccountTrigger on Account (before insert) {
if ( Trigger.isBefore && Trigger.isInsert)
{
AccountTriggerHandler.CreateAccounts(Trigger.new);
}
}
public class AccountTriggerHandler {
public static void CreateAccounts(List<Account> Accnts)
{
List<Account> ValidAccounts = new List<Account>();
for (Account a : Accnts) {
a.ShippingState = a.billingState;
ValidAccounts.add(a);
}
if (ValidAccounts.size() > 0) {
insert ValidAccounts;
}
}
}
All Answers
I have updated your code with a fix. See if it works
What I did was:
1. Changed the trigger to after update
2. Made sure that during committing back the "ShippingState = billingState" change to database, do an update instead of an insert.
After trigger runs after the record is saved (but not committed) to the database, so update is valid.
If this worked, mark this as best answer.
public class AccountTriggerHandler {
public static void CreateAccounts(List<Account> Accnts)
{
List<Account> ValidAccounts = new List<Account>();
for (Account a : Accnts) {
ValidAccounts.add(new Account(id=a.id, ShippingState = a.billingState,billingState = a.billingState));
}
if (ValidAccounts.size() > 0) {
update ValidAccounts;
}
}
}
but my unit test still didn't work so I also changed trigger handler to if (Trigger.isAfter && Trigger.isInsert) then it passed the unti tests but the challenge wouldn't validate as it was looking for isBefore so I added this to keep that happy
if (Trigger.isBefore || Trigger.isAfter && Trigger.isInsert)
Anyway unit tests and challenge completed now. thanks
Write an Apex trigger that modifies Account fields before inserting records.
Write an Apex trigger that fires before records are inserted and ensures that the ShippingState field has the same value as the BillingState field.
Basically, your trigger should only modify the Account records, not insert them. That is done automagically afterwards.
trigger AccountTrigger on Account (before insert)
{
if (Trigger.isBefore && Trigger.isInsert) {
AccountTriggerHandler.CreateAccounts(Trigger.new);
}
}
public class AccountTriggerHandler {
public static void CreateAccounts(List<Account> accts) {
for (Account a : accts) {
a.ShippingState = a.BillingState;
}
}
}
public with sharing class AccountTriggerHandler {
public static void CreateAccounts(List<Account> accnts){
for(Integer i=0;i<accnts.size();i++){
accnts.get(i).ShippingState = accnts.get(i).BillingState;
}
}
}
trigger AccountTrigger on Account (before insert) {
if(trigger.isBefore && trigger.isInsert){
AccountTriggerHandler.CreateAccounts(trigger.New);
}
}
@isTest
public class AccountTriggerTest {
@isTest
static void TestCreateAccountInBulk(){
List<Account> accntList = new List<Account>();
for(Integer i=0;i<200;i++){
Account account = new Account(Name='Test Accnt '+ i,BillingState='CA');
accntList.add(account);
}
Test.startTest();
insert accntList;
Test.stopTest();
List<Account> verifyAccnt = [SELECT Id FROM Account WHERE ShippingState='CA' AND BillingState='CA'];
System.assertEquals(200, verifyAccnt.size());
}
}
I was getting this error because the Name field was missing in Accounts created in the test class:
@isTest
public class AccountTriggerTest {
@isTest static void test1(){
List<Account> accountsList = new List<Account>();
for(Integer i=0;i<200;i++){
Account acc = new Account();
acc.Name = 'TestAccount '+i;
acc.BillingState = 'CA';
accountsList.add(acc);
}
Test.startTest();
insert accountsList;
Test.stopTest();
List<Account> retrievedAccounts = [SELECT Id from Account where ShippingState='CA'];
System.assertEquals(200,retrievedAccounts.size(),'The returned data is not correct');
}
}
After adding the 'Name' field, the test class ran successfully and I completed the challenge.