+ Start a Discussion
carmantcarmant 

Make trigger only fire on PersonAccount, not Account

Hi,

 

Our org uses Person Accounts.

 

This trigger I wrote works perfectly when creating a Person Account. However it throws the following error when creating a normal business Account - 

 

System.QueryException: List has no rows for assignment to SObject: Trigger.CreateCase: line 14, column 1

 

Here is the trigger - 

 

//define trigger and when it fires
trigger CreateCase on Account (after insert) {


  //create list of cases to be inserted
  List<Case> newcase = new List<Case>();


  //find the ID of the correct record type
  Id rtId = [select Id, name from RecordType where name ='My Case Record Type' and SObjectType='Case' limit 1].Id;
  
  //find contact ID to attach to the to case
  Id personContact = [select id, Name from Contact where Contact.AccountId in : Trigger.New].Id;   

  // create some strings define criteria when the trigger fires
  for (Account acc: Trigger.New) {
  String corpacclink = acc.Corporate_Account_Link_Text__c;
  String mylink = 'My Link';
    if (corpacclink.contains(mylink))  
      {  
      //define what values to put against the new case
      newcase.add(new Case(
            AccountId = acc.Id,
            ContactId = personContact,
            RecordTypeId = rtId,
            Type='Welcome Call',
            Origin='Email',
            Status='Not Started',
            Call_Attempt__c='1'
            )
            );

      }
    
      //insert the new case(s)
      insert newcase;  
      }
  }

 

 

I understand WHY I am getting the error - the SOQL query looking for a Contact in line 14 isn't finding a Contact, because normal Accounts don't create Contacts (whilst Person Accounts do).

 

However - not sure how to fix this? Do I have to catch and handle the exception in some way? Or alternatively is there a way to get the trigger to only fire on Person Accounts?

 

Thanks!

Best Answer chosen by Admin (Salesforce Developers) 
Naidu PothiniNaidu Pothini
//define trigger and when it fires
Trigger CreateCase on Account (after insert) 
{
	//create list of cases to be inserted
	List<Case> newcase = new List<Case>();
	
	List<Id> accIds = new List<Id>();
	for(Account a : Trigger.New)
	{
		if(a.IsPersonAccount)
		{
			accIds.add(a.Id);
		}
	}
	
	Map<Id,Id> accConMap = new Map<Id,Id>();
	
	for(Contact con : [SELECT Id, Name, AccountId FROM Contact WHERE AccountId IN :accIds])
	{
		accConMap.put(con.AccountId, con.Id);
	}
	
	Id rtId = [select Id, name from RecordType where name ='My Case Record Type' and SObjectType='Case' limit 1].Id;

  // create some strings define criteria when the trigger fires
  
	for (Account acc: Trigger.New) 
	{
		if(acc.IsPersonAccount)
		{
			String corpacclink = acc.Corporate_Account_Link_Text__c;
			String mylink = 'My Link';
			if (corpacclink.contains(mylink))  
			{  
				//define what values to put against the new case
				newcase.add(new Case(
					AccountId = acc.Id,
					ContactId = accConMap.get(acc.Id),
					RecordTypeId = rtId,
					Type='Welcome Call',
					Origin='Email',
					Status='Not Started',
					Call_Attempt__c='1'
					)
					);

			}
			
			//insert the new case(s)
			insert newcase;  
		}
	}
}

 

 

Now try this. :Let me know if it doesnt work.

All Answers

New_DeveloperNew_Developer

May be you can put a condition like this

 

Id personContact = [select id, Name from Contact where Contact.AccountId IN : trigger.new and

Contact.Account.RecordTypeId = 'your person Account recordtype id'].id

Damien_Damien_

There are several reasons why you can get errors on this line.  

 

1) The reason you are running into is because you are telling it to associated with EXACTLY 1 account and 0 are returned from the query.  

2) Potentially a single account could have multiple contacts that could look up to it which would cause too many to be returned.

3) Also  your trigger can fire on multiple accounts at a time, which each account can have anywhere from 0 to many Contacts.

 

Your fix:

List<Contact> contacts = [select id, Name from Contact where Contact.AccountId in :Trigger.new];   
Naidu PothiniNaidu Pothini
//define trigger and when it fires
Trigger CreateCase on Account (after insert) 
{
	Id PersonAccountRecordTypeId = [SELECT Id, Name FROM RecordType WHERE Name = 'Person Account'];   // Use the name of the record type for person accounts
	
	//create list of cases to be inserted
	List<Case> newcase = new List<Case>();
	
	List<Id> accIds = new List<Id>();
	for(Account a : Trigger.New)
	{
		if(a.RecordTypeId == PersonAccountRecordTypeId)
		{
			accIds.add(a.Id);
		}
	}
	
	Map<Id,Id> accConMap = new Map<Id,Id>();
	
	for(Contact con : [SELECT Id, Name, AccountId FROM Contact WHERE AccountId IN :accIds])
	{
		accConMap.put(con.AccountId, con.Id);
	}
	
	Id rtId = [select Id, name from RecordType where name ='My Case Record Type' and SObjectType='Case' limit 1].Id;

  // create some strings define criteria when the trigger fires
  
	for (Account acc: Trigger.New) 
	{
		if(acc.RecordtypeId == PersonAccountRecordTypeId)
		{
			String corpacclink = acc.Corporate_Account_Link_Text__c;
			String mylink = 'My Link';
			if (corpacclink.contains(mylink))  
			{  
				//define what values to put against the new case
				newcase.add(new Case(
					AccountId = acc.Id,
					ContactId = accConMap.get(acc.Id),
					RecordTypeId = rtId,
					Type='Welcome Call',
					Origin='Email',
					Status='Not Started',
					Call_Attempt__c='1'
					)
					);

			}
			
			//insert the new case(s)
			insert newcase;  
		}
	}
}

 Try this.

Marty Y. ChangMarty Y. Chang

Hello, carmant,

 

Our org uses Person Accounts as well.  From my testing, you should be able to do use the standard Account.IsPersonAccount field to isolate the Person Accounts in your trigger and then operate only on those accounts, without having to use SOQL!

 

The code pattern would look something like this:

 

// Compile list of Person Accounts in the trigger.

List<Account> newPersonAccounts = new List<Account>();

for (Account account : Trigger.new) {
    if (account.IsPersonAccount)
        newPersonAccounts.add(account);
}   // for each Account in Trigger.new

// Now, do what you want with newPersonAcounts...

 

Naidu PothiniNaidu Pothini
//define trigger and when it fires
Trigger CreateCase on Account (after insert) 
{
	//create list of cases to be inserted
	List<Case> newcase = new List<Case>();
	
	List<Id> accIds = new List<Id>();
	for(Account a : Trigger.New)
	{
		if(a.IsPersonAccount)
		{
			accIds.add(a.Id);
		}
	}
	
	Map<Id,Id> accConMap = new Map<Id,Id>();
	
	for(Contact con : [SELECT Id, Name, AccountId FROM Contact WHERE AccountId IN :accIds])
	{
		accConMap.put(con.AccountId, con.Id);
	}
	
	Id rtId = [select Id, name from RecordType where name ='My Case Record Type' and SObjectType='Case' limit 1].Id;

  // create some strings define criteria when the trigger fires
  
	for (Account acc: Trigger.New) 
	{
		if(acc.IsPersonAccount)
		{
			String corpacclink = acc.Corporate_Account_Link_Text__c;
			String mylink = 'My Link';
			if (corpacclink.contains(mylink))  
			{  
				//define what values to put against the new case
				newcase.add(new Case(
					AccountId = acc.Id,
					ContactId = accConMap.get(acc.Id),
					RecordTypeId = rtId,
					Type='Welcome Call',
					Origin='Email',
					Status='Not Started',
					Call_Attempt__c='1'
					)
					);

			}
			
			//insert the new case(s)
			insert newcase;  
		}
	}
}

 

 

Now try this. :Let me know if it doesnt work.

This was selected as the best answer
carmantcarmant

Thanks Damien and Marty for your info, that helped.

 

In the end I used Naidu's suggestion - worked perfectly.

 

Just to ensure I understand:

 

- Its creating a list of Account IDs, but only for PersonAccounts created by the trigger

- It creates a Map which looks up the corresponding ContactId for the Accounts in the list.

- It inserts the ID to the case by using the Map .get method to lookup the ContactId for the provided AccountId

 

 

Thanks!