function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
LFILFI 

Need help creating trigger for junction object Contacts Roster

Hello,
I am helping a local non-profit and created a SalesForce system for them. I am learning in the process and have no prior experiene with Apex or SalesForce. The organization does training and need to be able to generate rosters from Contacts. I added two custom fields to the default Contacts object, called Alumni_Type (3 letters) and Alumni_Year (4 letters). Also created a Roster custom object with fields for Roster_Name, Alumni_Type and Alumni_Year. The idea is to be able to create a new Roster object by giving it Name, Alumni_Type and Alumni_Year, then the system will automatically pull a list of all the contacts that have the same values for Alumni_Type and and Alumni_Year in the Contacts object. I was advised on another blog that this can be done with a junction object and a trigger. So then I created ContactRosterAssociation custom object, with two fields. One is Contact__c Master-Detail(Contact) field and the other is Roster__c  Master-Detail(Roster) field. I might need to add more fields. I'm at the point where the trigger needs to be created, and have no clue how to proceed. Can anyone help me with the Apex code? Any help is appreciated!
Best Answer chosen by LFI
LFILFI
Got it! The issue was the name of the variable lstContact_to_Roster_Association__c. Not sure if it is too long or the fact that it has __c, but after I changed it to lstContactAssociations and it works perfect! Now I need to figure out how to push this to my production instance :)

Thank you so much Sandeep! You were great help and I actually learned something in the process :). I know a little Java and this code looks very similar.

Here is the final code:
trigger rosterTrigger on Roster__c  (after insert) {
    
        public set<String> strTypes = new set<String>();
        public set<String> strYears = new set<String>();
        public list<Contact> lstContact = new list<Contact>();
        public list<Contact_to_Roster_Association__c> lstContactAssociations = new list<Contact_to_Roster_Association__c> ();
        
         for(Roster__c objRoster : trigger.new)
         {
             strTypes.add(objRoster.Program_Type__c);
             strYears.add(objRoster.Program_Year__c);
         }
                 
         for(Contact objContact : [Select Id ,Alumni_Type__c,  Alumni_Year__c from Contact where Alumni_Type__c IN:  strTypes OR Alumni_Year__c IN : strYears])
         {
             
             if(objContact.Alumni_Type__c !=null && objContact.Alumni_Year__c !=null)
             {
                 lstContact.add(objContact);
             }
             
         }
        
         for(Roster__c objC : trigger.new)
         {
             for(Contact objContact : lstContact)
            {
                Contact_to_Roster_Association__c objRA = new Contact_to_Roster_Association__c();
                objRA.Contact__c = objContact.Id;
                objRA.Roster__c = objC.Id;
                lstContactAssociations.add(objRA);
            }
         }
        
        if(!lstContactAssociations.isEmpty())
        {
            insert lstContactAssociations;
        }
}

All Answers

sandeep sankhlasandeep sankhla
Hi LFI,

Let me know if you have already achieved above req...or need any help ?
LFILFI
Hello Sandeep! I would really appreciate if you can help with the trigger code.
I have the junction object and relationships created. I can create a new Roster and pick Contacts with lookup to add, one by one. Now if I can get this the contacts to be added automatically, it would be perfect! There are about 100 contacts for each year, so doing it manually it is tedious/unreasonable.
The idea is when I create a new Roster object by giving it Name, Alumni_Type and Alumni_Year, then the system will automatically generate the associations list of all the contacts that have the same values for Alumni_Type and and Alumni_Year in the Contacts object. I give it I've done some basic programming with other languages, but I've never written Apex code before. I don't even know where do I start?  Thanks in advance!
sandeep sankhlasandeep sankhla
Hi LFI,
 
So here basically you need somthing like..

Whenever we insert Roster record with all fields it should check all matching contact and insert all of them in a junction record with contact and same roster..

Please confirm this...
LFILFI
You got it!
sandeep sankhlasandeep sankhla
Hi LFI,

Thanks! Give me some time tio check..
LFILFI
Here is more info for the objects. Hope it helps

(default) Contact
Alumni_Type__c: Text
Alumni_Year__c: Text

Custom Object1 name and fields
API Name: Roster__c 
Program_Type__c: Picklist
Program_Year__c: Picklist
Project_Topics__c: Rich Text Area(32768)

Custom Object2 name and fields
API Name: Contact_to_Roster_Association__c
Contact__c: Master-Detail(Contact)
Roster__c: Master-Detail(Roster)
sandeep sankhlasandeep sankhla
Hi LFI,


I am running late so I have just written a trigger for you but this will work for only single record which means you can insert manually oen by one Roster record and it will find all contact record and create a junction records with same roster id and contcats..

please check with belwo code and correct syntax error..

You can try this it will help you to reduce manual work...

dont insert bulk record as a temprory solution I have given the code so you can isnert one roster record manually and then it will create junction record for the same..

please test this if it helps you..and let me know if you need naything I will try to connect with you...

trigger rosterTrigger on Roster__c  (after insert) {
    
        set<String> strTypes = new set<String>();
        set<Decimal> strYears = new set<Decimal>();
        list<Contact> lstContact = new list<Contact>();
        
        
         for(Roster__c objRoster : trigger.new)
         {
             strTypes.add(objRoster.Alumni_Type__c);
             strYears.add(objRoster.Alumni_Year__c);
         }
         
         
         for(Contact objContact : [Select Id ,Alumni_Type__c,  Alumni_Year__c from Contact where Alumni_Type__c IN:  strTypes OR Alumni_Year__c IN : strYears])
         {
             
             if(objContact.Alumni_Type__c !=null && objContact.Alumni_Year__c !=null)
             {
                 lstContact.add(objContact);
             }
             
         }
         
        list<Contact_to_Roster_Association__c> lstContact_to_Roster_Association__c = new Contact_to_Roster_Association__c();
        
         for(Roster__c objC : trigger.new)
         {
             for(Contact objAccount : lstContact)
            {
                Contact_to_Roster_Association__c objRA = new Contact_to_Roster_Association__c();
                objRA.Contact__c = objAccount.Id;
                objRA.Roster__c = objC.Id;
                lstContact_to_Roster_Association__c.add(objRA);
            }
         }
        
        if(!lstContact_to_Roster_Association__c.isEmpty())
        {
            insert lstContact_to_Roster_Association__c;
        }
}

P.S. If my answer helps you to solve your problem please mark it as best answer. It will help other to find best answer.

Thanks,
Sandeep
Salesforce Certified Developer 
LFILFI

Thansk Sandeep!
The code won't compile yet. I fixed couple of the errors, but stuck on this one Error: Compile Error: Illegal assignment from Contact_to_Roster_Association__c to List<Contact_to_Roster_Association__c> at line 25 column 9

The things I changed were the strYears type is a String and these lines to reflect the correct field name:
strTypes.add(objRoster.Alumni_Type__c); changed to strTypes.add(objRoster.Program_Type__c);
strYears.add(objRoster.Alumni_Year__c); changed to strYears.add(objRoster.Program_Year__c);
 
trigger rosterTrigger on Roster__c  (after insert) {
    
        set<String> strTypes = new set<String>();
        set<String> strYears = new set<String>();
        list<Contact> lstContact = new list<Contact>();
        
        
         for(Roster__c objRoster : trigger.new)
         {
             strTypes.add(objRoster.Program_Type__c);
             strYears.add(objRoster.Program_Year__c);
         }
         
         
         for(Contact objContact : [Select Id ,Alumni_Type__c,  Alumni_Year__c from Contact where Alumni_Type__c IN:  strTypes OR Alumni_Year__c IN : strYears])
         {
             
             if(objContact.Alumni_Type__c !=null && objContact.Alumni_Year__c !=null)
             {
                 lstContact.add(objContact);
             }
             
         }
         
        list<Contact_to_Roster_Association__c> lstContact_to_Roster_Association__c = new Contact_to_Roster_Association__c();
        
         for(Roster__c objC : trigger.new)
         {
             for(Contact objAccount : lstContact)
            {
                Contact_to_Roster_Association__c objRA = new Contact_to_Roster_Association__c();
                objRA.Contact__c = objAccount.Id;
                objRA.Roster__c = objC.Id;
                lstContact_to_Roster_Association__c.add(objRA);
            }
         }
        
        if(!lstContact_to_Roster_Association__c.isEmpty())
        {
            insert lstContact_to_Roster_Association__c;
        }
}

 
sandeep sankhlasandeep sankhla
Hi LFI,

Please replace line 25 with this below line

 list<Contact_to_Roster_Association__c> lstContact_to_Roster_Association__c = new list<Contact_to_Roster_Association__c> ();

Please check and let me know
LFILFI
I did that and let me save it. Then when I go to create a new roster, getting this now: Error: Invalid Data. 
Review all error messages below to correct your data.
Apex trigger rosterTrigger caused an unexpected exception, contact your administrator: rosterTrigger: execution of AfterInsert caused by: line 25, column 48: trigger body is invalid and failed recompilation: Invalid identifier: lstContact_to_Roster_Association__c
LFILFI
Looking at lines 29-32, isn't the objAccount supposed to be objContact? Most of my contacts don't have accounts I think.
sandeep sankhlasandeep sankhla
Hi LFI,

Can you paste the final code which you ahev modified so I can haev a look..adn regarding line no 29 that is just a wrong naming conventio nothing else..

Plesae paste your code here...
LFILFI
This is the code the is saved in the trigger now. The only thing I changed  was line 25 per your previous reply. If I try to edit and save it again, without making any changes, it wont save anymore and complains about line 25.

trigger rosterTrigger on Roster__c  (after insert) {
    
        set<String> strTypes = new set<String>();
        set<String> strYears = new set<String>();
        list<Contact> lstContact = new list<Contact>();
        
        
         for(Roster__c objRoster : trigger.new)
         {
             strTypes.add(objRoster.Program_Type__c);
             strYears.add(objRoster.Program_Year__c);
         }
         
         
         for(Contact objContact : [Select Id ,Alumni_Type__c,  Alumni_Year__c from Contact where Alumni_Type__c IN:  strTypes OR Alumni_Year__c IN : strYears])
         {
             
             if(objContact.Alumni_Type__c !=null && objContact.Alumni_Year__c !=null)
             {
                 lstContact.add(objContact);
             }
             
         }
         
        list<Contact_to_Roster_Association__c> lstContact_to_Roster_Association__c = new list<Contact_to_Roster_Association__c> ();
        
         for(Roster__c objC : trigger.new)
         {
             for(Contact objAccount : lstContact)
            {
                Contact_to_Roster_Association__c objRA = new Contact_to_Roster_Association__c();
                objRA.Contact__c = objAccount.Id;
                objRA.Roster__c = objC.Id;
                lstContact_to_Roster_Association__c.add(objRA);
            }
         }
        
        if(!lstContact_to_Roster_Association__c.isEmpty())
        {
            insert lstContact_to_Roster_Association__c;
        }
sandeep sankhlasandeep sankhla
Hi LFI,

Replace your entire code with thsi code and check

trigger rosterTrigger on Roster__c  (after insert) {
    
        public set<String> strTypes = new set<String>();
        public set<String> strYears = new set<String>();
        public list<Contact> lstContact = new list<Contact>();
        public list<Contact_to_Roster_Association__c> lstContact_to_Roster_Association__c = new list<Contact_to_Roster_Association__c> ();
        
         for(Roster__c objRoster : trigger.new)
         {
             strTypes.add(objRoster.Program_Type__c);
             strYears.add(objRoster.Program_Year__c);
         }
         
         
         for(Contact objContact : [Select Id ,Alumni_Type__c,  Alumni_Year__c from Contact where Alumni_Type__c IN:  strTypes OR Alumni_Year__c IN : strYears])
         {
             
             if(objContact.Alumni_Type__c !=null && objContact.Alumni_Year__c !=null)
             {
                 lstContact.add(objContact);
             }
             
         }
         
        
        
         for(Roster__c objC : trigger.new)
         {
             for(Contact objAccount : lstContact)
            {
                Contact_to_Roster_Association__c objRA = new Contact_to_Roster_Association__c();
                objRA.Contact__c = objAccount.Id;
                objRA.Roster__c = objC.Id;
                lstContact_to_Roster_Association__c.add(objRA);
            }
         }
        
        if(!lstContact_to_Roster_Association__c.isEmpty())
        {
            insert lstContact_to_Roster_Association__c;
        }
LFILFI
Got it! The issue was the name of the variable lstContact_to_Roster_Association__c. Not sure if it is too long or the fact that it has __c, but after I changed it to lstContactAssociations and it works perfect! Now I need to figure out how to push this to my production instance :)

Thank you so much Sandeep! You were great help and I actually learned something in the process :). I know a little Java and this code looks very similar.

Here is the final code:
trigger rosterTrigger on Roster__c  (after insert) {
    
        public set<String> strTypes = new set<String>();
        public set<String> strYears = new set<String>();
        public list<Contact> lstContact = new list<Contact>();
        public list<Contact_to_Roster_Association__c> lstContactAssociations = new list<Contact_to_Roster_Association__c> ();
        
         for(Roster__c objRoster : trigger.new)
         {
             strTypes.add(objRoster.Program_Type__c);
             strYears.add(objRoster.Program_Year__c);
         }
                 
         for(Contact objContact : [Select Id ,Alumni_Type__c,  Alumni_Year__c from Contact where Alumni_Type__c IN:  strTypes OR Alumni_Year__c IN : strYears])
         {
             
             if(objContact.Alumni_Type__c !=null && objContact.Alumni_Year__c !=null)
             {
                 lstContact.add(objContact);
             }
             
         }
        
         for(Roster__c objC : trigger.new)
         {
             for(Contact objContact : lstContact)
            {
                Contact_to_Roster_Association__c objRA = new Contact_to_Roster_Association__c();
                objRA.Contact__c = objContact.Id;
                objRA.Roster__c = objC.Id;
                lstContactAssociations.add(objRA);
            }
         }
        
        if(!lstContactAssociations.isEmpty())
        {
            insert lstContactAssociations;
        }
}
This was selected as the best answer
sandeep sankhlasandeep sankhla
Thanks LFI,

Feel free to reach out to me for any doubts..
LFILFI
Appreciate it! Now can I do a fresh upload from Production (I've done changes there) to the Sandbox, add the trigger, and then push back to Production? Not sure if there will be any conflicts anywhere.
sandeep sankhlasandeep sankhla
Hi LFI,

This is a temprory solution I have provided you , it will always work when you manually insert Roster record but if you will do bulk insert from data loader then it will not work...so you can decide based on your req if it will be alwas manual then you can go ahead with this else I will check if gets time I will give you the code for bulk also..

In order to push code to prodcution you need to write a test class and then push it from changeset...

 
LFILFI
This is fine, there won't be bulk imports of rosters, only contacts.
LFILFI
Do you know what this error means? I tried to depoloy the trigger to production.
Code Coverage Failure
Your organization's code coverage is 0%. You need at least 75% coverage to complete this deployment. Also, the following triggers have 0% code coverage. Each trigger must have at least 1% code coverage.rosterTrigger

rosterTrigger; null, Details: Test coverage of selected Apex Trigger is 0%, at least 1% test coverage is required; Average test coverage across all Apex Classes and Triggers is 0%, at least 75% test coverage is required.
sandeep sankhlasandeep sankhla
Hi LFI,

This is what I was telling, you need to write a test class for this trigger...

To cover the code for this you can create one test class and insert below code there it will cover your code...

Contact objContact = new Contact(LastName='Tst');
objContact.Alumni_Type__c = 'testType';
objContact.Alumni_Year__c  = '2002';
insert objContact;

Roster__c objR = new Roster__c ();
objR.Program_Type__c = 'testType';
objR.Program_Year__c = '2002';

insert objR;


P.S. If my answer helps you to solve your problem please mark it as best answer. It will help other to find best answer.

Thanks,
Sandeep
Salesforce Certified Developer 

 
sandeep sankhlasandeep sankhla
Hi LFI,

That is fine, that you can keep as it is so people can refer the trigger code if they also have the same requirnmnets...

I was telling for test class...so there are people those are not aware can take help how to write test class..

Thanks
Sandeep
LFILFI
I started a new discussion here https://developer.salesforce.com/forums/ForumsMain?id=906F0000000B32pIAC . So close, just need to deploy it :)