0

I am new into the apex development. I am getting an this error in my map:

Invalid initializer type List found for Map expected a Map with the same key and value types, or a valid SObject List

Why do I get this error? How can I fix it?

Here is the code:

Trigger LastOnsiteVisit_SA on Event(Before insert, before update) {
    Set<ID> eventIds = new Set<ID>();
    Set<ID> AccountIDZ = new Set<ID>();

    for (Event evt: Trigger.New) {

        eventIds.add(evt.Id);

        AccountIDZ.add(evt.AccountId);
    }

    Set<Account> Accountset = new Set<Account>([SELECT ID FROM Account where ID IN: AccountIDZ]);

    Map<Id,Datetime> mp2 = new Map<Id,Datetime> ([SELECT AccountId, EndDateTime FROM Event WHERE RecordTypeId = '01270000000YSks' 
                                              AND AccountId IN :AccountIDZ 
                                              AND Type = 'Onsite Meeting' 
                                              ORDER BY EndDateTime DESC]);

    for (Account acct: Accountset) {
        if (mp2.containskey(acct.id)) {
            acct.Last_Onsite_Visit__c = mp2.get(acct.Id).Date();

        }
    }
}
  • 1
    You can't instantiate a Map of type: Map<Id, Datetime> by using a queried list of Event. Your mp2 map is of type: Map<Id, Event>. Also, the Id stored in the map as key will be the Id of the Event, not the one of the Account. – Martin Lezer Aug 2 '17 at 12:43
  • @MartinLezer - I believe that is the proper answer :) – Eric Aug 2 '17 at 12:47
4

It's worth noting that you can create this trigger functionality without writing a single line of code if you just install the Declarative Lookup Rollup Summaries tool and configure the corresponding Lookup Rollup Summary.


The closest constructor which would be valid is to use new Map<Id, SObject>(List<SObject>). That would look like:

Map<Id, Event> events = new Map<Id, Event>([/*query*/]);

This constructor will map each record by its own Id. If you want to map each AccountId to the corresponding EndDateTime, you will have to roll your own map. Note that there can be multiple records matching the same key, so you have to decide whether you want to just clobber the results, get the most recent value, etc.

A typical pattern for doing the mapping yourself would be:

Map<Id, List<Datetime>> times = new Map<Id, List<Datetime>>();
for (Event record : [/*query*/])
{
    if (!times.containsKey(record.AccountId))
        times.put(record.AccountId, new List<Datetime>());
    times.get(record.AccountId).add(record.EndDateTime);
}

You could also use a clever aliasing trick to, for example, get the most recent timestamp for each AccountId:

Map<Id, AggregateResult> mostRecent = new Map<Id, AggregateResult>([
    SELECT AccountId Id, MAX(EndDateTime) EndDateTime FROM Event
    WHERE ...
]);

With this map in hand, you will consume much less CPU time getting the data you need. Note also that you do not need to query for a record to update it. If you already know its Id, you can just construct a record with that Id and you're good to go.

List<Account> accounts = new List<Account>();
for (Id accountId : mostRecent.keySet())
{
    accounts.add(new Account(
        Id=accountId, MyDateField__c=mostRecent.get(accountId).get('EndDateTime')
    ));
}
update accounts;

If you get a chance, you should look at best practices around error handling and logic-less trigger bodies (using a trigger handler pattern).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.