+ Start a Discussion

Confused about StandardSetController behavior

I'm using a standard set controller to update multiple records displayed in a grid. I'm passing the IDs for the records to the VF page in the URL in one parameter, comma separated. in the setController property, I'm pulling out those IDs, querying the database, then returning the related records.


The problem is that when I try to save the records, they're not changing. 


I can see what's happening -- when my save() method gets the records to update from the setController, it's going through the same routine to pull the records from the database. Of course, that's not what I want.


I tested, and if (after the page is rendered), I comment out the database logic in the setController, the setController only has the updated records and the save performs correctly.


For now, I've written a clugy work-around that checks to see if the number of records in the setController are the same as the number of IDs I've passed to the page. If there's more, I know that I'm rendering the visualforce page -- if they're the same, I *assume* that I'm trying to save the records - and I bypass the database logic. But this is prone to bugs...


Here's the code. Any hints on a better approach would be appreciated.



public ApexPages.StandardSetController setController { get { String[] shipmentIds = EncodingUtil.urlDecode(ApexPages.currentPage().getParameters().get('Ids'), 'UTF-8').split(','); if (setController.getRecords().size() > shipmentIds.size()) { String query = 'Select Id, Name, Status__c, SalesOrder__c From Shipment__c Where '; for (String id : shipmentIds) { query += 'Id = \'' + id + '\' Or '; } query = query.substring(0, query.length()-4); List<Shipment__c> shipments = new List<Shipment__c>(); try { shipments = Database.query(query); } catch (System.Queryexception e) {} setController = new ApexPages.StandardSetController(shipments); } return setController; } set; }





As I'm thinking through this more, I think a better approach would be to loop through the records that are returned in the StandardSetController from the outset, and extract those that match the Ids I've passed through.


The problem is that this doesn't seem very efficient - looping through potentially thousands of (unsorted) records looking for anywhere from 1-10 specific records... I suppose I could loop through once and populate a new Map with the key being the ID, then get the records directly...


Just thinking out loud -- any thoughts?


So I implemented that approach, but now when I try to save the records, I get an error: "Modified rows exist in the records collection!"


Here's the updated controller:



public ApexPages.StandardSetController setController {
get {
// build a map to make searching quicker
Map<Id, Shipment__c> allShipments = new Map<Id, Shipment__c>();
boolean hasNext = true;
while (hasNext){
for (Shipment__c s : (List<Shipment__c>) setController.getRecords()) { allShipments.put(s.Id, s); }
if (setController.getHasNext()) setController.next();
else hasNext = false;

// extract the shipments we're looking for
String[] shipmentIds = EncodingUtil.urlDecode(ApexPages.currentPage().getParameters().get('Ids'), 'UTF-8').split(',');
List<Shipment__c> shipments = new List<Shipment__c>();
for (String id : shipmentIds) { shipments.add(allShipments.get((Id) id)); }

// rebuild the setController and return it
setController = new ApexPages.StandardSetController(shipments);
return setController;





I wouldn't go the StandardSetController route myself - as you've seen, you're losing control over behaviour and you're also not benefiting from the additional functionality it provides.


Once you've extracted the ids you are interested in from the URL, you can easily pull back just those using the following SOQL:


List<Shipment__c> shipments=[select <fields> from Shipments__c where Shipment__c.id in :shipmentIds];


If you bind these to the various elements in your grid, you can save them all in one go by using:



update shipments;


(obviously I've shown the shipments as a local variable and then used it in another method, but you get the point).




please provide a working example of this


i am doing with the approach that u mentioned (by passing the database logic )still not able to get the new values from the page, can u please share the solution