5

I know that Salesforce does not support lambda expressions and query syntax (like in LINQ) queries in apex collections. But, It would be a nice feature for developers.

Has anyone tried implementing similar kind of thing in Apex ? I found this github link where someone tried this, but its too big a package to include in the project.

For example

List<Opportunity> opportunities = new List<Opportunity>();
opportunities = [SELECT Id, Amount, StageName from Opportunity LIMIT 49000];
List<Opportunity> hugeOpportunities = opportunities.Where(o => o.Amount > 40000);


List<Opportunity> opportunities = new List<Opportunity>();
opportunities = [SELECT Id, Amount, StageName from Opportunity LIMIT 49000];
List<Opportunity> hugeOpportunities = from o in opportunities 
                                      where o.Amount > 40000
                                      select o;

Also, I can see an idea here, but somehow it has not yet received the votes needed to get picked by Salesforce.

Does Salesforce have any plans to implement this in future. Features that would be very useful as a developer would be to have support for

  • Anonymous classes
  • Lambda expressions (similar to method syntax of LINQ in C#)
  • Query syntax (similar to query syntax of LINQ in C#)

Can someone please suggest me an alternative for this, using which I can query on the collections without having to worry about the CPU time limit?

2
  • Vijay, curious what you mean by "it's too big a package to include". I was thinking of using that package in a project of my own and hadn't thought size might be an issue. Sep 19, 2019 at 21:48
  • It depends on how big a project you are working on, if you are reaching the apex character limit of 3,000,000 and if you need this feature only in couple of places, then it's better to write multiple SOQL queries rather than importing around 40 new classes. If this feature is needed in multiple places and character limit is not a problem, then you can go ahead with that package. Sep 20, 2019 at 2:59

3 Answers 3

3

Can't speak for Salesforce's future plans, but...

Filtering on the order of 10K - 100K records shouldn't end up being too time consuming.

If you're not filtering on a general list of records multiple times, then the best option is probably to just include your filter as part of your initial query.

Probably the closest thing that you'll find to what you're looking for (besides that Apex Lambdas package) is bluewolf-beyond's Selector project. Looks like it hasn't been touched in a few years.

Given a list of SObjects, you could (with this package),

// N.B. I don't actually have this package installed anywhere
// This is my best guess at how the syntax would look, given my limited time with the docs
List<Opportunity> filtered = (List<Opportunity>)(Select.Field.greaterThan(Opportunity.Amount, 40000).filter(oppsList));
1
  • Thanks for the reply @Derek. I am trying to filer on a common list of records multiple times. I am getting around 30k records in a list and trying to filter those records multiple times. If I apply the filter on SOQL itself, then I will have to do multiple SOQL's, which again might lead to hitting the SOQL governor limits. I went through bluewolf-beyond's selector project, it too has 49 classes which needs to be imported. By the way, thanks again for the suggestion. Feb 13, 2019 at 6:04
2

I'm the author of the apex-lambda library that you mentioned. I believe it's the closest thing to what you looking for on the platform. As Apex is a very static language, you have to reify (i.e. "make into classes") all the type-related things that would be avoided through generics.

If 3,000,000 characters are a risk, a library that provides many functional concepts should reduce the number of characters. Instead of writing long loops, you can just describe what you want. So on one hand, library code is added, but you get savings every time you use that code.

CPU time limit is a real concern, but that's a trade-off against SQL queries. If you are working with large dataset, you might be pleased to know that I've recently added Stream-like behaviour that allows you to lazily iterate instead of eagerly computing.

Salesforce does not seem to be moving in that direction. Instead of improving their language, they chose to support “serverless” functions in more popular languages instead.

0

in your class put this line of code.

List<Account> accounts = Apx.filterRecords(accounts, Account.Name, 'sampleAccount');

add to your utility class the Apx Functions.

public virtual class Apx {

      /**
 *  @description Filter List of Sobject by field value
 *  @param typeName - objectTypeName;
 **/
public static List<SObject> filterRecords(List<SObject> records, SObjectField fieldName, Object value) {
    List<SObject> filteredRecords = new List<SObject>();
    String fieldval, stringVal;
    String fieldType = fieldName.getDescribe().getType().name();
    try {
        stringVal = Apx.setValueByType(value, fieldType);
    }catch(Exception ex) {
        System.debug(' ** Apx.filterRecords() ERROR, probably a the value is not a string field. field: ' + fieldName);
        System.debug(ex);
        return new List<SObject>();
    }
    for(SObject record : records){
        try {
            fieldval =  Apx.setValueByType(record.get(fieldName), fieldType);
        } catch(Exception e) {
            System.debug(' ** Apx.filterRecords() ERROR, probably a the value is not a string field. field: ' + fieldName);
            System.debug(e);
            return new List<SObject>();
        }
        if(fieldval != null && fieldval.equalsIgnoreCase(stringVal)) filteredRecords.add(record);
    }
    return filteredRecords;
}

public static String setValueByType(Object newValue, String dataType){
    String stringVal, newValueString;
    Decimal newDecimal;
    try{
        switch on dataType {
            //using string for phone, not significant enough.
            when 'REFERENCE', 'PICKLIST', 'STRING', 'PHONE', 'EMAIL', 'URL', 'MULTIPICKLIST','BOOLEAN'{
                stringVal = String.valueOf(newValue);
            }
            when 'DATE'{
                Date myDate = (Date)newValue;
                stringVal = myDate.format();
            }
            when 'DATETIME'{
                Datetime myDateTime = (Datetime)newValue;
                stringVal = myDateTime.format();
            }
            when 'INTEGER', 'DECIMAL', 'CURRENCY','DOUBLE'{
                newDecimal = (Decimal)newValue;
                stringVal = String.valueOf(newDecimal);
                
            }
            when else{
                Apx.sendAdminEmail('Did not find field type', 'the field type was: ' + dataType + ' and the val: ' + newValue);
            }
        }
        newValueString = stringVal;
        return newValueString;
    }
    catch(Exception e){
        Apx.sendAdminEmail('Error converting value to string.', 'new value:' + newValue + '. Error:' + e.getStackTraceString());
        return '';
    }
}
    }

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .