fflib-apex-common
fflib-apex-common copied to clipboard
QueryFactory support: For Update
A handy enhancement would be a new fluent method on fflib_QueryFactory that supports the For Update clause
.addForUpdate()
the addForUdpate would do a getOrderings().clear() as you can't Order By with For Update. This would avoid code within a Selector class like this:
public override String getOrderby() {return 'OrderItemNumber';}
/* other selector methods here... */
public virtual OrderItem[] selectSomethingCoolAvoidLockingIssues(set<ID> ids) {
fflib_QueryFactory oiQF = newQueryFactory()
.setCondition('Id IN :ids' +
' AND Type__c IN (\'FOO\',\'BAR\')' );
oiQF.getOrderings().clear(); // no Order BY if FOR UPDATE
String soql = oiQF.toSOQL() + ' FOR UPDATE';
return Database.query(soql);
}
Oooh yes, nice one!
Would you be able to do a PR? I am sure @agarciaodeian and team would be happy to review. 👍
I'll consider myself challenged to do the PR -- have to unbury myself from existing real-world work first :-(
@agarciaffdc this looks like a good enhancement idea, maybe in the meantime use the tag feature to highlight it as an enhancement?
Here's some updates I made directly to fflib_QueryFactory to give us this functionality. Sorry I don't have time to do a PR, but hope it helps others in the meantime.
Added Method
/**
* Add 'FOR UPDATE' query modifer, useful for locking records during update.
**/
public pattern_QueryFactory forUpdate(){
this.forUpdate = true;
return this;
}
New forUpdate property
private Boolean forUpdate;
Updated toSOQL() method
/**
* Convert the values provided to this instance into a full SOQL string for use with Database.query
* Check to see if subqueries queries need to be added after the field list.
**/
public String toSOQL(){
String result = 'SELECT ';
//if no fields have been added, just add the Id field so that the query or subquery will not just fail
if (fields.size() == 0){
if (enforceFLS) pattern_SecurityUtils.checkFieldIsReadable(table, 'Id');
result += 'Id';
}else {
List<String> fieldsToQuery = new List<String>(fields);
if(sortSelectFields){
fieldsToQuery.sort();
}
result += String.join(fieldsToQuery,', ');
}
if(subselectQueryMap != null && !subselectQueryMap.isEmpty()){
for (pattern_QueryFactory childRow : subselectQueryMap.values()){
result += ', (' + childRow.toSOQL() + ') ';
}
}
result += ' FROM ' + (relationship != null ? relationship.getRelationshipName() : table.getDescribe().getName());
if(conditionExpression != null)
result += ' WHERE '+conditionExpression;
// add result ordering
result += getOrderBy();
if(limitCount != null)
result += ' LIMIT '+limitCount;
if(offsetCount != null)
result += ' OFFSET '+offsetCount;
if(forUpdate)
result += ' FOR UPDATE';
return result;
}
Would be great to have this PR updated.
@sureshkp87 and others reading this.
The team is actively exploring the best approach with managing "criteria class based query factories". This PR is not the only proposed approach and we have been reviewing the merits of alternative approaches verses this approach.
While we appreciate the delay is annoying, we are working to make the best choice on this question. You will appreciate that once the decision is made, there will be no looking back. ;-)
@sureshkp87 and others reading this.
The team is actively exploring the best approach with managing "criteria class based query factories". This PR is not the only proposed approach and we have been reviewing the merits of alternative approaches verses this approach.
While we appreciate the delay is annoying, we are working to make the best choice on this question. You will appreciate that once the decision is made, there will be no looking back. ;-)
Hello, I am just writing to find out if any decision was made regarding this issue. Thanks!