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
MohsinWadeeMohsinWadee 

Apply Domain Layer Principles in Apex challenge

Cannot get this to work - get the error:

Challenge Not yet complete... here's what's wrong: 
The 'Accounts' class 'onBeforeUpdate' method does not appear to be calculating the Levenshtein distance between the phrase default Description ‘Domain classes rock!’ and the value in the updated Description and storing the result in the Annual Revenue field correctly.

Here's my code in the Accounts class:
 
public class Accounts extends fflib_SObjectDomain {

    public Accounts(List<Account> sObjectList) {
        super(sObjectList);
    }
    
    public class Constructor implements fflib_SObjectDomain.IConstructable {
        public fflib_SObjectDomain construct(List<sObject> sObjectList) {
            return new Accounts(sObjectList);
        }
    }
    
    public override void onBeforeInsert() {
        List<Account> newAccounts = new List<Account>();
        
        for (Account acct : (List<Account>) Records) {
            acct.Description = 'Domain classes rock!';
            newAccounts.add(acct);
        }
        
        fflib_SObjectUnitOfWork uow = new fflib_SObjectUnitOfWork(new Schema.SObjectType[] { Account.SObjectType });
        uow.registerNew(newAccounts);
    }
    
    public override void onBeforeUpdate(Map<Id,sObject> Records) {
        String rock = 'Domain classes rock!';
        Set<Id> Ids = Records.keySet();
        
        List<Account> accountList = [SELECT Id, Description, AnnualRevenue 
                                     FROM Account 
                                     WHERE Id IN :Ids];
        
        List<Account> updatedAccounts = new List<Account>();
        
        for (Account acct : accountList) {
            if (acct.Description != NULL) {
                acct.AnnualRevenue = rock.getLevenshteinDistance(acct.Description);
                updatedAccounts.add(acct);
            }
        }
        
        fflib_SObjectUnitOfWork uow = new fflib_SObjectUnitOfWork(new Schema.SObjectType[] { Account.SObjectType });
        uow.registerDirty(updatedAccounts);
    }
    
    public override void onApplyDefaults() {
        String rock = 'Domain classes rock!';
        List<Account> accountList = (List<Account>)Records;
        List<Account> updatedAccounts = new List<Account>();
        
        for (Account acct : accountList) {
            if (acct.Description != NULL) {
                acct.AnnualRevenue = rock.getLevenshteinDistance(acct.Description);
                updatedAccounts.add(acct);
            }
        }
        
        fflib_SObjectUnitOfWork uow = new fflib_SObjectUnitOfWork(new Schema.SObjectType[] { Account.SObjectType });
        uow.registerDirty(updatedAccounts);
        uow.commitWork();
    }
}

 
Best Answer chosen by MohsinWadee
Son DinhSon Dinh
my function
public override void onBeforeUpdate(Map<Id,sObject> existingRecords) {
        String rock = 'Domain classes rock!';
        List<Account> updatedAccounts = new List<Account>();
        for(Account acc : (List<Account>) Records) {                  
            acc.AnnualRevenue = rock.getLevenshteinDistance(acc.Description);
            updatedAccounts.add(acc);
        }
       
        fflib_SObjectUnitOfWork uow = new fflib_SObjectUnitOfWork(new Schema.SObjectType[] { Account.SObjectType });
        uow.registerDirty(updatedAccounts);
    }

All Answers

MohsinWadeeMohsinWadee
This is the trigger:
 
trigger AccountsTrigger on Account (before insert, before update, before delete, after insert, after update, after delete) {
	
    fflib_SObjectDomain.triggerHandler(Accounts.class);
}

 
Son DinhSon Dinh
I found the problem
Change the input parameter like
public override void onBeforeUpdate(Map<Id,sObject> existingRecords) {

Because records is as the same the property Records. Salesforce is case sensetive
Son DinhSon Dinh
my function
public override void onBeforeUpdate(Map<Id,sObject> existingRecords) {
        String rock = 'Domain classes rock!';
        List<Account> updatedAccounts = new List<Account>();
        for(Account acc : (List<Account>) Records) {                  
            acc.AnnualRevenue = rock.getLevenshteinDistance(acc.Description);
            updatedAccounts.add(acc);
        }
       
        fflib_SObjectUnitOfWork uow = new fflib_SObjectUnitOfWork(new Schema.SObjectType[] { Account.SObjectType });
        uow.registerDirty(updatedAccounts);
    }
This was selected as the best answer
MohsinWadeeMohsinWadee
thanks that worked.
Neil Neil 
public class Accounts extends fflib_SObjectDomain  {
    public Accounts(List<Account> sObjectList) {
        super(sObjectList);
    }
    
    public class Constructor implements fflib_SObjectDomain.IConstructable {
        public fflib_SObjectDomain construct(List<sObject> sObjectList) {
            return new Accounts(sObjectList);
        }
    }
    

    public override void onBeforeUpdate(Map<Id,sObject> existingRecords) {
		String phrase = 'Domain classes rock!';
        for(Account account : (List<Account>) Records) {
            account.AnnualRevenue = phrase.getLevenshteinDistance(account.Description);
        }
    }
    
    public override void onApplyDefaults() {
         for (Account account : (List<Account>) Records) {
            account.Description = 'Domain classes rock!';
        }
    }   
}
Moshin - 'my 2c if I may : ...  I noticed a lot of extra code in your Challange answer. The above snippet seems to work and bag the 500 points. We use our own simplified  domain framework but I believe Andy's framework works something like this (I may be wrong, but this is my mental mapping) ...:  For the insert and Delete operations only one collection is defined - for Insert it is the New collection and for Delete, it is the Old collection - in either case, the appropriate  collection is surfaced to you in the Records property automatically - Now with the Update operation it's a coin toss - I believe Andy chose to assign the New collection to the Records property. That means, the Old collection must be injected into the OnBeforeUpdate method as a parameter -  for this  challange we don't actually use it. Also, since we are using the Before Handler, we get to update the collection by simple assignment - no UOW pattern required.
DORA KOTTHRUDORA KOTTHRU
I am getting  Invalid type: fflib_SObjectDomain , I am trying to create as APex class , may be I am wrong, Not sure what is the category like class , object , trigger for Domain class creation.  Please help me to resolve this 

Error
Jacob BarnettJacob Barnett
I'm getting an error when trying to save the trigger on this challenge and not sure as to why. Everything looks correct to me:

Error: Compile Error: Cannot save a trigger during a parse and save class call at line -1 column -1
 
trigger AccountsTrigger on Account (before insert, before update, before delete, after insert, after update, after delete) 
    {
        fflib_SObjectDomain.triggerHandler(Accounts.class);
    }
What am I missing?
Carlos Naranjo 15Carlos Naranjo 15

Guys, we are executing a Before Trigger context here... you don't need any uow on this case.
The Before Trigger context will take care of that for you.