The big thing about fieldsets is that they're declarative. If you define a fieldset, and use that in visualforce/apex, you can change the fields that are displayed in visualforce, or processed in apex, without modifying code. This also means that, in my org, I can (safely) change behavior in production without the need for a deployment.
Probably the best example I personally have of this is the custom "mass edit" tool that I developed for my org. From an Opportunity
, my users can click a button that brings them to a visualforce page. There, they can select the OpportunityLineItems
that they want to edit. From there, my fieldset determines what fields they are allowed to edit en masse.
If I want to change the fields available for editing, I simply add/remove things from the fieldset (my unit tests for that code also use the fieldset).
Outside of visualforce, fieldsets can also be used if you want to roll your own declarative rollup summary tool. Something like
List<String> rollupFields = new List<String>();
for(Schema.FieldSetMember f : SObjectType.OpportunityLineItem.FieldSets.OliRollupFields.getFields()) {
// To use fields from a fieldset in a query, we need to get the field path
// (which returns the api name of the field)
rollupFields.add(f.getFieldPath());
}
// String.join() allows us to easily take a list of strings, and put commas between them.
// Using String.join(), we don't need to worry about extra comma(s) at the beginning or end.
// String.join() isn't enough to put the field names in between the parenthesis
// of 'SUM()', so we need to use replaceAll() to take care of that.
// The regex matches valid field names (alphanumeric + underscores) and stores them
// in captured group 1.
// In the 'replace' string, $1 is substituted with the value stored in that numbered
// captured group.
// 'a_field__c, b_field__c' would become 'SUM(a_field__c) a_field__c, SUM(b_field__c) b_field__c
String aggFunctions = String.join(rollupFields, ', ').replaceAll('([a-zA-Z0-9_]+(__c)?)', 'SUM($1) $1');
String queryString = 'SELECT OpportunityId, ' + aggFunctions + ' FROM OpportunityLineItem WHERE OpportunityId IN :oppIds GROUP BY OpportunityId';
List<Opportunity> oppsToUpdate = new List<Opportunity>();
for(AggregateResult ar :database.query(queryString)){
Opportunity tempOpp = new Opportunity(Id = (Id)ar.get('OpportunityId'));
for(String field :rollupFields){
tempOpp.put(field, (Decimal)ar.get(field) == null ? 0 : (Decimal)ar.get(field));
}
oppsToUpdate.add(tempOpp);
}
update oppsToUpdate;