• Zach Carter
  • NEWBIE
  • 25 Points
  • Member since 2012

  • Chatter
    Feed
  • 1
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 3
    Questions
  • 13
    Replies

Hi,

 

I've been tasked to create an opportunity roll up on one of our custom objects AM_Performance__c.  I need to put the number of opportunitites owned by the certain user.

 

I figured what I could do is get a list of owner ids, then get query opportunity to get all of the opportuities owned by that owner id, then write size of that list to the AM_Performance__c object.  Problem is that I am getting this illegal assignment error on the line that's marked in red.  Can someone help?

 

Thanks!

 

 

trigger AMPROppCount on Opportunity (after insert, after update, after delete, after undelete) {

    //Create a Set to hold Acct Ids of opps in trigger and a List to hold accts which will be updated
    
    Set<Id> ownerIdSet = new Set<Id>();
    List<AM_Performance__c> amprUpdateList = new List<AM_Performance__c>();

    //Create ths set of Owner IDs.  If this is a delete trigger, pull them the trigger.old,
    //otherwise use trigger.new
    
    if(Trigger.isDelete)
        for(Opportunity o : trigger.old)
            ownerIdSet.add(o.OwnerId);
    else
        for(Opportunity o : trigger.new)
            ownerIdSet.add(o.OwnerId);

    //Query for all of the opportunities 
    List<AM_Performance__c> amprOpptyList = [select Id, OwnerId, IsWon, IsClosed from Opportunity where ownerId IN :ownerIdSet];

    //loop through all of the AM_Performance__cs in the map and get the counts for total number of opps,
    //count of closed and count of won opps.
    
    for(AM_Performance__c a : amprOpptyList){
        //initialize our counters
        Integer wonOpps = 0;
        Integer closedOpps = 0;

        //loop through the associated opportunities and count up the opportunities
        for(Opportunity o : a.Opportunities){
            if(o.IsClosed){
                closedOpps++;
                
            if(o.IsWon) wonOpps++;
            }
        }

        //set the counts
        a.Opportunities_Owned_This_Month__c = a.Opportunities.size();

        //add the AM_Performance__c to the update list
        amprUpdateList.add(a);
    }

    //update all of the AM_Performance__c's if the list isn't empty
    if(!amprUpdateList.IsEmpty())
update amprUpdateList; }

 

Hi all, I've been working on a fairly complicated trigger this week, and nested maps have been driving me crazy. Here's some background on the trigger :

 

The trigger fires upon a custom s-object being inserted or updated. This custom s-object holds references to two seperate accounts.

 

The point of the trigger is to create another custom s-object (basically a meet up object) to establish a relationship between the two accounts referenced by the object the trigger is firing on. So if the trigger was firing on custom object A which references Accounts A and B, the trigger would ideally create a new custom object C which would also reference accounts A and B.

 

This gets pretty tricky, especially when trying to 'bulkify' the trigger.

 

Here's a step by step description of the approach I took to write this trigger, and the problems I ran into / how I resolved them :

 

if(Trigger.isAfter && (Trigger.isInsert || Trigger.isUpdate)) {      
// List to hold newly created objects to insert List<Account_Partner__c> newAcctPartners = new List<Account_Partner__c>();
// Map to hold Ids of accounts referenced by object(s) trigger is firing on Map<Id,Id> accountIdMap = new Map<Id, Id>();

// Originally this was a Map<Map<Id,Id>, Known_Data_Type__c> but had to be converted to use a key of type String
// Map is used to store relationships between Id pairs and the object they are associated with Map<String, Known_Data_Type__c> kdtAccountMap = new Map<String, Known_Data_Type__c>();

// If the relationship object we are trying to create via the trigger already exists, this map will hold it
// along with whatever object the trigger is firing on, that it relates to Map<Known_Data_Type__c, Account_Partner__c> kdtAccountPartnerMap = new Map<Known_Data_Type__c, Account_Partner__c>();
// Here we iterate over our incoming objects, and if they are valid we store them along with their Ids in the maps we created for(Known_Data_Type__c kdt : Trigger.new) { if((Trigger.isInsert && kdt.Account__c != null && kdt.Data_Provider__c != null) || (Trigger.isUpdate && Trigger.oldMap.get(kdt.Id).Data_Provider__c != kdt.Data_Provider__c)) { accountIdMap.put(kdt.Data_Provider__c, kdt.Account__c); kdtAccountMap.put(kdt.Data_Provider__c + ',' + kdt.Account__c, kdt); kdtAccountPartnerMap.put(kdt, null); } }
// Here we retrieve any relationship objects which already exist - we don't want to establish the relationship twice Map<Id, Account> partnerAccountMap = new Map<Id,Account>([Select Id, Partner_Type__c FROM Account WHERE Id in :accountIdMap.keySet()]);
// I iterate over the retrieved relationship objects and using the map which relates Id pairs to the objects the trigger is firing on
// I fill out another map with the existing relationship object and the trigger object it is related to for(Account_Partner__c acctPartner : [Select Id, Partner_Account__c, Account__c FROM Account_Partner__c WHERE Account__c in :accountIdMap.values() AND Partner_Account__c in :accountIdMap.keySet()]) { String accountPartnerIdString = acctPartner.Partner_Account__c + ',' + acctPartner.Account__c; if(kdtAccountMap.containsKey(accountPartnerIdString)) { kdtAccountPartnerMap.put(kdtAccountMap.get(accountPartnerIdString), acctPartner); } }
// Finally iterate over all the valid objects the trigger is firing on
// If there isn't already a relationship object in existence which relates the two accounts the trigger objects references, then create and insert it for(Known_Data_Type__c kdt : kdtAccountPartnerMap.keySet()) { if(kdtAccountPartnerMap.get(kdt) == null) newAcctPartners.add(new Account_Partner__c(Account__c = kdt.Account__c, Partner_Account__c = kdt.Data_Provider__c, Partner_Role__c = partnerAccountMap.get(kdt.Data_Provider__c).Partner_Type__c)); } insert newAcctPartners; }

 

Hopefully your brain isn't hurting as much as mine was after getting to the end of that Trigger. Yes I know it needs to be split into helper methods, etc...

 

I emboldened, underlined and italicized some of the code above - these are the parts of code I struggled with the most. I had previously tried to use :

 

Map<Map<Id,Id>, Known_Data_Type__c> for the kdtAccountMap object. This didn't work however - it seems that even if the inner Map entries are different, the outer Map will treat them as duplicate keys.

 

So if I try to do something like :
kdtAccountMap.put(new Map<Id,Id> {id1, id2}, kdt1) 
kdtAccountMap.put(new Map<Id,Id> {id3, id4}, kdt1) 

I end up with a map that looks like - {{id3,id4} = kdt1} - where the heck did {id1, id2} go? I guess Apex isn't smart enough to figure out that the Key is actually a different map?

Even more strange was the result of trying to print this nested map to the console using System.debug

 

With only one entry the System.debug call would work fine, but as soon as the second entry had been added to the map the System.debug call would fail and a 'Internal Salesforce.com Error' would be thrown with no additional info.

 

This was so god **bleep** frustrating and I tried numerous work arounds -

 

1. Using a wrapper object as the key :

Class IdPair {

   public Id accountId{get;set;};

   public Id partnerAccountId{get;set;};

 

   public IdPair(Id accountId, Id partnerAccountId)

   {

      this.accountId = accountId;

      this.partnerAccountId = partnerAccountId

   }

}

 

Map<IdPair, Known_Data_Type__c>

 

This also failed and would also error out when trying to print out the map. Possibly because I didn't have a to string method, but it also seemed like the key was getting overwritten even if the IdPair was different from previous IdPairs added to the map.

 

2. Using an array of Ids as the key - same issues as above.

 

Why the heck doesn't this work? I'm probably doing something wrong / stupid but I'm not wasiting any more time on this so for now the hacky string contatenation will have to do.

 

Thanks,

 

- An extremely frustrated and confused Zach

Hello all,

 

I was wondering if there was any way inside of a test method, to assert the number of times a method is invoked or in this specific case, the number of times an object was updated.

 

I have a trigger which is responsible for updating an sObject, but only under certain conditions.

 

Besides asserting that the field has not been initialized, is there some way of ensuring that the sobject was not updated during the test / determining how many times the update method was called on the object?

 

If not, this would be a very nice feature for the apex language to have.

 

Thank you,

 

-Zach

Hello,

 

Let's say I have a bulk trigger andI only want to perform the business logic of the trigger when an sobject in the collection the trigger is operating on, has  a certain field filled out (not null).

 

Is the cheapest way to do this to iterate over the conents of the trigger until I find a sobject with a not null value in this field? Something like - 

 

for(Account a : Trigger.new) {
    if(a.customField != null) {

      // add object to collection

      ...

   }
}

 

This is O(N) and while I don't expect bulk creation of account objects to occur I suppose it is always possible.

 

I chose this option instead - 

 

Account[] changedAccounts = [SELECT Id, customField FROM Account WHERE Id IN :Trigger.new AND customField != null];

 

Then I iterate over this collection, however I have the EXACT collection I want.

 

I wish there were more fine grained control over when a trigger fires in Apex, but then again there are a lot of other more important features the language lacks so I suppose as long as I find the most efficient way to filter my result set I'll be happy for now.

 

Thanks,

 

-Zach

Hi all, I've been working on a fairly complicated trigger this week, and nested maps have been driving me crazy. Here's some background on the trigger :

 

The trigger fires upon a custom s-object being inserted or updated. This custom s-object holds references to two seperate accounts.

 

The point of the trigger is to create another custom s-object (basically a meet up object) to establish a relationship between the two accounts referenced by the object the trigger is firing on. So if the trigger was firing on custom object A which references Accounts A and B, the trigger would ideally create a new custom object C which would also reference accounts A and B.

 

This gets pretty tricky, especially when trying to 'bulkify' the trigger.

 

Here's a step by step description of the approach I took to write this trigger, and the problems I ran into / how I resolved them :

 

if(Trigger.isAfter && (Trigger.isInsert || Trigger.isUpdate)) {      
// List to hold newly created objects to insert List<Account_Partner__c> newAcctPartners = new List<Account_Partner__c>();
// Map to hold Ids of accounts referenced by object(s) trigger is firing on Map<Id,Id> accountIdMap = new Map<Id, Id>();

// Originally this was a Map<Map<Id,Id>, Known_Data_Type__c> but had to be converted to use a key of type String
// Map is used to store relationships between Id pairs and the object they are associated with Map<String, Known_Data_Type__c> kdtAccountMap = new Map<String, Known_Data_Type__c>();

// If the relationship object we are trying to create via the trigger already exists, this map will hold it
// along with whatever object the trigger is firing on, that it relates to Map<Known_Data_Type__c, Account_Partner__c> kdtAccountPartnerMap = new Map<Known_Data_Type__c, Account_Partner__c>();
// Here we iterate over our incoming objects, and if they are valid we store them along with their Ids in the maps we created for(Known_Data_Type__c kdt : Trigger.new) { if((Trigger.isInsert && kdt.Account__c != null && kdt.Data_Provider__c != null) || (Trigger.isUpdate && Trigger.oldMap.get(kdt.Id).Data_Provider__c != kdt.Data_Provider__c)) { accountIdMap.put(kdt.Data_Provider__c, kdt.Account__c); kdtAccountMap.put(kdt.Data_Provider__c + ',' + kdt.Account__c, kdt); kdtAccountPartnerMap.put(kdt, null); } }
// Here we retrieve any relationship objects which already exist - we don't want to establish the relationship twice Map<Id, Account> partnerAccountMap = new Map<Id,Account>([Select Id, Partner_Type__c FROM Account WHERE Id in :accountIdMap.keySet()]);
// I iterate over the retrieved relationship objects and using the map which relates Id pairs to the objects the trigger is firing on
// I fill out another map with the existing relationship object and the trigger object it is related to for(Account_Partner__c acctPartner : [Select Id, Partner_Account__c, Account__c FROM Account_Partner__c WHERE Account__c in :accountIdMap.values() AND Partner_Account__c in :accountIdMap.keySet()]) { String accountPartnerIdString = acctPartner.Partner_Account__c + ',' + acctPartner.Account__c; if(kdtAccountMap.containsKey(accountPartnerIdString)) { kdtAccountPartnerMap.put(kdtAccountMap.get(accountPartnerIdString), acctPartner); } }
// Finally iterate over all the valid objects the trigger is firing on
// If there isn't already a relationship object in existence which relates the two accounts the trigger objects references, then create and insert it for(Known_Data_Type__c kdt : kdtAccountPartnerMap.keySet()) { if(kdtAccountPartnerMap.get(kdt) == null) newAcctPartners.add(new Account_Partner__c(Account__c = kdt.Account__c, Partner_Account__c = kdt.Data_Provider__c, Partner_Role__c = partnerAccountMap.get(kdt.Data_Provider__c).Partner_Type__c)); } insert newAcctPartners; }

 

Hopefully your brain isn't hurting as much as mine was after getting to the end of that Trigger. Yes I know it needs to be split into helper methods, etc...

 

I emboldened, underlined and italicized some of the code above - these are the parts of code I struggled with the most. I had previously tried to use :

 

Map<Map<Id,Id>, Known_Data_Type__c> for the kdtAccountMap object. This didn't work however - it seems that even if the inner Map entries are different, the outer Map will treat them as duplicate keys.

 

So if I try to do something like :
kdtAccountMap.put(new Map<Id,Id> {id1, id2}, kdt1) 
kdtAccountMap.put(new Map<Id,Id> {id3, id4}, kdt1) 

I end up with a map that looks like - {{id3,id4} = kdt1} - where the heck did {id1, id2} go? I guess Apex isn't smart enough to figure out that the Key is actually a different map?

Even more strange was the result of trying to print this nested map to the console using System.debug

 

With only one entry the System.debug call would work fine, but as soon as the second entry had been added to the map the System.debug call would fail and a 'Internal Salesforce.com Error' would be thrown with no additional info.

 

This was so god **bleep** frustrating and I tried numerous work arounds -

 

1. Using a wrapper object as the key :

Class IdPair {

   public Id accountId{get;set;};

   public Id partnerAccountId{get;set;};

 

   public IdPair(Id accountId, Id partnerAccountId)

   {

      this.accountId = accountId;

      this.partnerAccountId = partnerAccountId

   }

}

 

Map<IdPair, Known_Data_Type__c>

 

This also failed and would also error out when trying to print out the map. Possibly because I didn't have a to string method, but it also seemed like the key was getting overwritten even if the IdPair was different from previous IdPairs added to the map.

 

2. Using an array of Ids as the key - same issues as above.

 

Why the heck doesn't this work? I'm probably doing something wrong / stupid but I'm not wasiting any more time on this so for now the hacky string contatenation will have to do.

 

Thanks,

 

- An extremely frustrated and confused Zach

I have a force site where I expose some custom and standard objects.

 

In the past I did this without any problems. But I keep getting this error.

I have an update button which calls and update to to account, causing the error.

 

I removed all of the update/upsert statements and I still get the error?

So, I have an update button, linking to a method that has no updates in it,

but I still get the error.

 

Any ideas?

Hi,

 

I've been tasked to create an opportunity roll up on one of our custom objects AM_Performance__c.  I need to put the number of opportunitites owned by the certain user.

 

I figured what I could do is get a list of owner ids, then get query opportunity to get all of the opportuities owned by that owner id, then write size of that list to the AM_Performance__c object.  Problem is that I am getting this illegal assignment error on the line that's marked in red.  Can someone help?

 

Thanks!

 

 

trigger AMPROppCount on Opportunity (after insert, after update, after delete, after undelete) {

    //Create a Set to hold Acct Ids of opps in trigger and a List to hold accts which will be updated
    
    Set<Id> ownerIdSet = new Set<Id>();
    List<AM_Performance__c> amprUpdateList = new List<AM_Performance__c>();

    //Create ths set of Owner IDs.  If this is a delete trigger, pull them the trigger.old,
    //otherwise use trigger.new
    
    if(Trigger.isDelete)
        for(Opportunity o : trigger.old)
            ownerIdSet.add(o.OwnerId);
    else
        for(Opportunity o : trigger.new)
            ownerIdSet.add(o.OwnerId);

    //Query for all of the opportunities 
    List<AM_Performance__c> amprOpptyList = [select Id, OwnerId, IsWon, IsClosed from Opportunity where ownerId IN :ownerIdSet];

    //loop through all of the AM_Performance__cs in the map and get the counts for total number of opps,
    //count of closed and count of won opps.
    
    for(AM_Performance__c a : amprOpptyList){
        //initialize our counters
        Integer wonOpps = 0;
        Integer closedOpps = 0;

        //loop through the associated opportunities and count up the opportunities
        for(Opportunity o : a.Opportunities){
            if(o.IsClosed){
                closedOpps++;
                
            if(o.IsWon) wonOpps++;
            }
        }

        //set the counts
        a.Opportunities_Owned_This_Month__c = a.Opportunities.size();

        //add the AM_Performance__c to the update list
        amprUpdateList.add(a);
    }

    //update all of the AM_Performance__c's if the list isn't empty
    if(!amprUpdateList.IsEmpty())
update amprUpdateList; }

 

Hello all,

 

I was wondering if there was any way inside of a test method, to assert the number of times a method is invoked or in this specific case, the number of times an object was updated.

 

I have a trigger which is responsible for updating an sObject, but only under certain conditions.

 

Besides asserting that the field has not been initialized, is there some way of ensuring that the sobject was not updated during the test / determining how many times the update method was called on the object?

 

If not, this would be a very nice feature for the apex language to have.

 

Thank you,

 

-Zach

Hi,

 

I am trying to develop an app which compares two salesforce instance.

I know i need to use Metadata API to ahieve this.

And i need to do this using Apex.

 

Please guide me on moving ahead with this.

I havent coded apex in a long time, this trigger was working for the past 8 months and then all the sudden we get this:

 

 

Apex script unhandled trigger exception by user/organization: 005U0000000fp0q/00DU0000000Kh8N

 

changeLeadStatus: execution of BeforeInsert

 

caused by: System.NullPointerException: Attempt to de-reference a null object

 

Trigger.changeLeadStatus: line 7, column 1

 

 

Any help would eb appricated

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

trigger changeLeadStatus on Task (before insert, before update) {
    String desiredNewLeadStatus = 'Working - Contacted';

    List<Id> leadIds=new List<Id>();
    for(Task t:trigger.new){
        if(t.Status=='Completed'){
            if(String.valueOf(t.whoId).startsWith('00Q')==TRUE){//check if the task is associated with a lead
                leadIds.add(t.whoId);
            }//if 2
        }//if 1
    }//for
    List<Lead> leadsToUpdate=[SELECT Id, Status FROM Lead WHERE Id IN :leadIds AND IsConverted=FALSE];
    For (Lead l:leadsToUpdate){
        l.Status=desiredNewLeadStatus;
    }//for
    
    try{
        update leadsToUpdate;
    }catch(DMLException e){
        system.debug('Leads were not all properly updated.  Error: '+e);
    }
}//trigger

Hello,

 

Let's say I have a bulk trigger andI only want to perform the business logic of the trigger when an sobject in the collection the trigger is operating on, has  a certain field filled out (not null).

 

Is the cheapest way to do this to iterate over the conents of the trigger until I find a sobject with a not null value in this field? Something like - 

 

for(Account a : Trigger.new) {
    if(a.customField != null) {

      // add object to collection

      ...

   }
}

 

This is O(N) and while I don't expect bulk creation of account objects to occur I suppose it is always possible.

 

I chose this option instead - 

 

Account[] changedAccounts = [SELECT Id, customField FROM Account WHERE Id IN :Trigger.new AND customField != null];

 

Then I iterate over this collection, however I have the EXACT collection I want.

 

I wish there were more fine grained control over when a trigger fires in Apex, but then again there are a lot of other more important features the language lacks so I suppose as long as I find the most efficient way to filter my result set I'll be happy for now.

 

Thanks,

 

-Zach