0

This is my query:

String query = 'SELECT Project__c, Project__r.Testing_Submitted__c, Project__r.Project_Sub_Phase__c, Project__r.DRD_Submited__c,Protected_Application__r.DRD_Completed__c, Protected_Application__c, Project__r.Id, Project__r.Name, Project__r.Project_Type__c, Project__r.Remark__c, Project__r.Record_Type_Name__c, Project__r.RecordTypeId, Project__r.Project_Actual_Completion__c,Protected_Application__r.Application__c, Project__r.Project_Phase__c, Project__r.Ready_for_Testing__c, Project__r.recordType.DeveloperName, Project__r.Project_Sub_Status__c,Project__r.Certification_was_submitted__c, Project__r.Customer_confirmed_launch_date__c,Protected_Application__r.Application_Type__c FROM ProjectAppLink__c ';

As you can see, it's a long string and I'd like to break it to several parts so it would be easier to read.

I tried using '\n' and '+' but when I try these I then get this error:

line breaks not allowed in string literals
  • it would also be nice if you would post what you have actually tried. Because according to what you said(I tried using '\n' and '+') I would assume that you did actually try using +, which is a right way to concatenate strings. We could also point out where you went wrong so that you wouldn't make this mistake in the future – Novarg Nov 30 '16 at 14:18
5

The following should allow you to make your query easier to read.

String query = 'SELECT Project__c,'
                  + ' Project__r.Testing_Submitted__c,'
                  + ' Project__r.Project_Sub_Phase__c,'
                  + ' Project__r.DRD_Submited__c,'
                  + ' Protected_Application__r.DRD_Completed__c,'
                  + ' Protected_Application__c,'
                  + ' Project__r.Id,'
                  + ' Project__r.Name,'
                  + ' Project__r.Project_Type__c,'
                  + ' Project__r.Remark__c,'
                  + ' Project__r.Record_Type_Name__c,'
                  + ' Project__r.RecordTypeId,'
                  + ' Project__r.Project_Actual_Completion__c,'
                  + ' Protected_Application__r.Application__c,'
                  + ' Project__r.Project_Phase__c,'
                  + ' Project__r.Ready_for_Testing__c,'
                  + ' Project__r.recordType.DeveloperName,'
                  + ' Project__r.Project_Sub_Status__c,'
                  + ' Project__r.Certification_was_submitted__c,'
                  + ' Project__r.Customer_confirmed_launch_date__c,'
                  + ' Protected_Application__r.Application_Type__c'
                + ' FROM ProjectAppLink__c ';

System.debug(query);
  • @Barracks the above String has no compile / runtime errors when displaying for System.debug(). You may have introduced an error at some stage because at no point does my answer include "Here's the full query: –". – TSmith Dec 1 '16 at 12:16
  • You are correct - I posted a new question: salesforce.stackexchange.com/questions/150852/… – Json Dec 1 '16 at 12:18
3

In addition to @TSmiths answer, you can also do the following:

String query = 'SELECT Project__c, Project__r.Testing_Submitted__c,'
query += ' Project__r.Project_Sub_Phase__c, Project__r.DRD_Submited__c,Protected_Application__r.DRD_Completed__c,'
query += ' Protected_Application__c, Project__r.Id, Project__r.Name, '
query += ' Project__r.Project_Type__c, Project__r.Remark__c, Project__r.Record_Type_Name__c, '
query += ' Project__r.RecordTypeId, Project__r.Project_Actual_Completion__c,Protected_Application__r.Application__c,'
query += ' Project__r.Project_Phase__c, Project__r.Ready_for_Testing__c, Project__r.recordType.DeveloperName,'
query += ' Project__r.Project_Sub_Status__c,Project__r.Certification_was_submitted__c, Project__r.Customer_confirmed_launch_date__c,'
query += ' Protected_Application__r.Application_Type__c'; 
query += ' FROM ProjectAppLink__c ';

What's happening here is you're initialising the variable query as a String and constantly appending to it.

+= is the same as doing query = query + 'some text', or:

Set the value of query by taking the value of query and adding "some text" to it.

2

In a slightly different vein from the two answers before me, you can use a List<String> along with String.join(List<String> source, String glue) to build a dynamic query.

The main benefit of this approach is that you reduce the work that needs to be done to add or remove fields from your query.

// Using curly braces allows us to directly initialize the list
// I'm using an empty line to distinguish between fields on different objects, though however you 
//   want to organize it is your choice.
List<String> fieldsToQuery = new List<String>{
    'Project__c',
    'Project__r.Testing_Submitted__c', 'Project__r.Project_Sub_Phase__c', 'Project__r.DRD_Submited__c'
    'Project__r.Id', 'Project__r.Name', 'Project__r.Project_Type__c', 'Project__r.Remark__c', 
    'Project__r.Record_Type_Name__c', 'Project__r.RecordTypeId', 'Project__r.Project_Actual_Completion__c',
    'Project__r.Project_Phase__c', 'Project__r.Ready_for_Testing__c', 'Project__r.recordType.DeveloperName', 'Project__r.Project_Sub_Status__c',
    'Project__r.Certification_was_submitted__c', 'Project__r.Customer_confirmed_launch_date__c',

    'Protected_Application__c', 
    'Protected_Application__r.DRD_Completed__c', 'Protected_Application__r.Application__c',
    'Protected_Application__r.Application_Type__c' 
};

// This query remains largely untouched.
// Changing the fields that you query doesn't require a change to this line
String query = 'SELECT ' + String.join(fieldsToQuery, ', ') + ' FROM ProjectAppLink__c';

The particularly nice thing about using String.join() is that you don't need to worry about comma placement. The strings in your field list are also simply the api names of the target fields.

It's also not too far a stretch from here to go more declarative, and use a fieldset to define which fields you'll query. Separating the fields from the query certainly doesn't do any favors for readability, but being able to change the queried fields without the need for a deployment can be nice.

+edit:

Adding in some benchmarks of solutions given so far. I used the following anon apex to perform all 3 solutions, 20k times each (to get a good sample):

Decimal time1;
Decimal time2;
Decimal cpuTime1;
Decimal cpuTime2;
Integer iterations = 20000;

Decimal bareLoop;
Decimal bareLoopCpu;
Decimal straightConcat;
Decimal straightConcatCpu;
Decimal plusEquals;
Decimal plusEqualsCpu;
Decimal stringJoin;
Decimal stringJoinCpu;

cpuTime1 = Limits.getCpuTime();
time1 = System.now().getTime();
for(Integer i = 0; i < iterations; i++){
}
time2 = System.now().getTime();
cpuTime2 = Limits.getCpuTime();
bareLoop = time2 - time1;
bareLoopCpu = cpuTime2-cpuTime1;

String query;

List<String> fieldsToQuery = new List<String>{
    'Project__c',
    'Project__r.Testing_Submitted__c', 'Project__r.Project_Sub_Phase__c', 'Project__r.DRD_Submited__c',
    'Project__r.Id', 'Project__r.Name', 'Project__r.Project_Type__c', 'Project__r.Remark__c', 
    'Project__r.Record_Type_Name__c', 'Project__r.RecordTypeId', 'Project__r.Project_Actual_Completion__c',
    'Project__r.Project_Phase__c', 'Project__r.Ready_for_Testing__c', 'Project__r.recordType.DeveloperName', 'Project__r.Project_Sub_Status__c',
    'Project__r.Certification_was_submitted__c', 'Project__r.Customer_confirmed_launch_date__c',

    'Protected_Application__c', 
    'Protected_Application__r.DRD_Completed__c', 'Protected_Application__r.Application__c',
    'Protected_Application__r.Application_Type__c' 
};

cpuTime1 = Limits.getCpuTime();
time1 = System.now().getTime();
for(Integer i = 0; i < iterations; i++){
    query = 'SELECT Project__c,'
                  + ' Project__r.Testing_Submitted__c,'
                  + ' Project__r.Project_Sub_Phase__c,'
                  + ' Project__r.DRD_Submited__c,'
                  + ' Protected_Application__r.DRD_Completed__c,'
                  + ' Protected_Application__c,'
                  + ' Project__r.Id,'
                  + ' Project__r.Name,'
                  + ' Project__r.Project_Type__c,'
                  + ' Project__r.Remark__c,'
                  + ' Project__r.Record_Type_Name__c,'
                  + ' Project__r.RecordTypeId,'
                  + ' Project__r.Project_Actual_Completion__c,'
                  + ' Protected_Application__r.Application__c,'
                  + ' Project__r.Project_Phase__c,'
                  + ' Project__r.Ready_for_Testing__c,'
                  + ' Project__r.recordType.DeveloperName,'
                  + ' Project__r.Project_Sub_Status__c,'
                  + ' Project__r.Certification_was_submitted__c,'
                  + ' Project__r.Customer_confirmed_launch_date__c,'
                  + ' Protected_Application__r.Application_Type__c'
                + ' FROM ProjectAppLink__c ';
}
time2 = System.now().getTime();
cpuTime2 = Limits.getCpuTime();

straightConcat = time2 - time1 - bareLoop;
straightConcatCpu = cpuTime2 - cpuTime1 - bareLoopCpu;

cpuTime1 = Limits.getCpuTime();
time1 = System.now().getTime();
for(Integer i = 0; i < iterations; i++){
    query = 'SELECT Project__c, Project__r.Testing_Submitted__c,';
    query += ' Project__r.Project_Sub_Phase__c, Project__r.DRD_Submited__c,Protected_Application__r.DRD_Completed__c,';
    query += ' Protected_Application__c, Project__r.Id, Project__r.Name, ';
    query += ' Project__r.Project_Type__c, Project__r.Remark__c, Project__r.Record_Type_Name__c, ';
    query += ' Project__r.RecordTypeId, Project__r.Project_Actual_Completion__c,Protected_Application__r.Application__c,';
    query += ' Project__r.Project_Phase__c, Project__r.Ready_for_Testing__c, Project__r.recordType.DeveloperName,';
    query += ' Project__r.Project_Sub_Status__c,Project__r.Certification_was_submitted__c, Project__r.Customer_confirmed_launch_date__c,';
    query += ' Protected_Application__r.Application_Type__c'; 
    query += ' FROM ProjectAppLink__c ';
}
time2 = System.now().getTime();
cpuTime2 = Limits.getCpuTime();

plusEquals = time2 - time1 - bareLoop;
plusEqualsCpu = cpuTime2 - cpuTime1 - bareLoopCpu;

cpuTime1 = Limits.getCpuTime();
time1 = System.now().getTime();
for(Integer i = 0; i < iterations; i++){
    query = 'SELECT ' + String.join(fieldsToQuery, ', ') + ' FROM ProjectAppLink__c';
}
time2 = System.now().getTime();
cpuTime2 = Limits.getCpuTime();

stringJoin = time2 - time1 - bareLoop;
stringJoinCpu = cpuTime2 - cpuTime1 - bareLoopCpu;


system.debug('Time taken in bare loop (just instantiating, comparing, and incrementing i): ' + bareLoop + '(' + bareLoopCpu + ' cpu time)');
system.debug('Time taken for direct concatenation (minus bareLoop): ' + straightConcat  + '(' + straightConcatCpu + ' cpu time)');
system.debug('direct concatenation (minus bareLoop) time per iteration: ' + (straightConcat / iterations)  + '(' + (straightConcatCpu / iterations) + ' cpu time)');
system.debug('Time taken for using query += string (minus bareLoop): ' + plusEquals  + '(' + plusEqualsCpu + ' cpu time)');
system.debug('query += string (minus bareLoop) time per iteration: ' + (plusEquals / iterations)  + '(' + (plusEqualsCpu / iterations) + ' cpu time)');
system.debug('Time taken for String.join() (minus bareLoop): ' + stringJoin  + '(' + stringJoinCpu + ' cpu time)');
system.debug('String.join() (minus bareLoop) time per iteration: ' + (stringJoin / iterations)  + '(' + (stringJoinCpu / iterations) + ' cpu time)');

results:

Time taken in bare loop (just instantiating, comparing, and incrementing i): 28 (16 cpu time)

Time taken for direct concatenation (minus bareLoop): 24 (10 cpu time)

direct concatenation (minus bareLoop) time per iteration: 0.0012 (0.0005 cpu time)

Time taken for using query += string (minus bareLoop): 648 (348 cpu time)

query += string (minus bareLoop) time per iteration: 0.0324 (0.0174 cpu time)

Time taken for String.join() (minus bareLoop): 1548 (970 cpu time)

String.join() (minus bareLoop) time per iteration: 0.0774 (0.0485 cpu time)

Conclusions:

  • Even the slowest of the 3 solutions (using String.join()) for all 100 allowed queries (in a synchronous transaction) won't amount to much of a delay.
    • 7.74ms (4.85 units of the CPU limit) vs 0.12ms (0.05 units of the CPU limit)
  • Choosing between these 3 solutions should probably not be based on the relative performance. If you're that pressed for headroom on the CPU governor limit, there are probably bigger gains to be claimed elsewhere.
  • I like this way, I'd be interested to know how efficient it is compared to just concatenating Strings. – Dan Jones Nov 30 '16 at 14:50
  • Concatenating strings is likely faster, though with a limit of 100 queries per transaction, any difference will probably be negligible. – Derek F Nov 30 '16 at 14:53
  • Also like this way as a dynamic approach. List could be populated in many ways and allows query to remain untouched. Good shout. Efficiency results would be good as a comparison. – TSmith Nov 30 '16 at 14:56
  • 1
    @DanJones benchmark is up – Derek F Nov 30 '16 at 15:36
  • @TSmith benchmark is up – Derek F Nov 30 '16 at 15:36

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.