7

I am facing this issue while uploading the data using CSV file on VF page with above 1000 Records.

Can any one please help me to overcome this issue.

Here is my code :

public class ItemsUploaderclass
{


    public String[] filelines {get;set;}

    public List<Items__c> uploadlist;


    public ItemsUploaderclass(ApexPages.StandardController controller) {

        filelines = new String[]{};
        uploadlist = new List<Items__c>();
    }

    // Method to read csv file
    public Pagereference ReadFile()
    {

        String[] errors = new List<String>();
        map<String,String> nameToCode = new map<String,String>();
        boolean check = false;

        for (Integer i=1;i<filelines.size();i++){
            String[] inputvalues = new String[]{};
            inputvalues = filelines[i].split(',');
            isoCodeRep = false;
            if(inputvalues.size() == 1) {
                continue;
            }



            Items__c item = new Items__c();
            if(inputvalues[0] != ''){ item.Item_Number__c = inputvalues[0];
            }

            if(inputvalues[1] != '') {item.codeABC__c = inputvalues[1];}
            if(inputvalues[2] != '') {item.Code_XYZ__c = inputvalues[2];}

            if(inputvalues[3] != '') { item.Unit__c = inputvalues[3]; }

            if(inputvalues[4] != '') { item.price__C = inputvalues[4]; }



            if((item.Name!= null && item.Quantity__c != null && item.UnitPrice__c != null && item.CurrencyIsoCode != null && item.Opportunity__c != null && item.Name != 'N/A' && (!isoCodeRep) ))
            {

                uploadlist.add(item);
            }

            else

            ApexPages.addmessage(new ApexPages.Message(ApexPages.severity.FATAL,'Error uploading the items  with number :'+ item.Item_Number__c ));


        }
        if (ApexPages.hasMessages(ApexPages.Severity.FATAL)){
            ApexPages.addmessage(new ApexPages.Message(ApexPages.severity.WARNING,'Upload Failed'));
            return null;
        }

        else
        try{
            insert uploadlist;
            ApexPages.addmessage(new ApexPages.Message(ApexPages.severity.INFO,'File Uploaded Successfully'));
        }catch (Exception e){
            System.debug('Error when inserting item scrubs:' + e);
            ApexPages.Message errormsg = new ApexPages.Message(ApexPages.severity.ERROR,'Error uploading the new item:' + e);

            return null;
        }



    }
    else{   //Display error message when no CSV file is chosen
        ApexPages.addMessage(new ApexPages.Message(ApexPages.severity.ERROR,'Please choose a valid CSV file'));
    }

    return null;
}

public List<Items__c> getuploadeditem()
{
    if (uploadlist!= NULL)
        if (uploadlist.size() > 0)
            return uploadlist;
        else
            return null;
        else
            return null;
    }


}

VF page :

 <apex:pageblocktable value="{!uploadeditem}" var="item" rendered="{!NOT(ISNULL(uploadeditem))}">

          <apex:column headerValue="Number"> 
              <apex:outputText value="{!item.Item_Number__c}"/>
          </apex:column>


          <apex:column headerValue="Unit">
              <apex:outputField value="{!item.Unit__c}"/>
          </apex:column>

          <apex:column headerValue="Price">
              <apex:outputField value="{!item.price__C}"/>
          </apex:column>



     </apex:pageblocktable> 
9

There is one simple trick to by pass the collection size limit on page.

Instead of using list of objects just use any map like Map<Id,SObject> and your page will never show this error again.


Update : Code for demonstration

Page :

<apex:page controller="AccountLister">
   <apex:form >
        <apex:pageBlock >
           <apex:pageBlockTable value="{!AccountMap}" var="accId">
                <apex:column value="{!AccountMap[accId].Name}"/>
                <apex:column value="{!AccountMap[accId].Type}"/>
            </apex:pageBlockTable>
        </apex:pageBlock>
  </apex:form>
</apex:page>

Controller :

public class AccountLister {
     public Map<ID, Account> AccountMap {get;set;}
    public AccountLister() {
       AccountMap = new Map<ID, account>([SELECT Id, Name, Type FROM Account]);
    }
}

Make sure Account has more than 1000 records for testing.


Update 2 : Maintaining the sort order of records.

Page :

<apex:page controller="AccountLister">
   <apex:form >
        <apex:pageBlock >
           <apex:pageBlockTable value="{!AccountMap}" var="accId">
                <apex:column value="{!AccountMap[accId].Name}"/>
                <apex:column value="{!AccountMap[accId].Type}"/>
                <apex:column value="{!AccountMap[accId].CreatedDate}"/>
            </apex:pageBlockTable>
        </apex:pageBlock>
  </apex:form>
</apex:page>

Controller :

public class AccountLister {
     public Map<Integer , Account> AccountMap {get;set;}
    public AccountLister() {
        AccountMap = new Map<Integer , Account>();
       List<Account> AccountList = [SELECT Id, Name, Type, CreatedDate 
                                          FROM Account
                                          Order By Name];

       for(Integer index = 0 ; index < AccountList.size() ; index++) {
           AccountMap.put(index, AccountList[index]);
       }
    }
}
| improve this answer | |
  • 3
    a Map is also a collection, how does this bypass the VF limit? Can you demonstrate here? – Mark Pond Aug 1 '16 at 18:34
  • @Mark your question is obvious and I have done this many times, just query on any sobject where it should has more than 1000 records and you will not have any difficulty in showing any number of records unless and until view is within limit. – Ishwar Mete Aug 1 '16 at 18:42
  • 4
    I made an example using Map<String, String> with 8000 records in it bound to a pageBlockTable and it rendered without error. This behavior is "new", the VF collection limit has been 1000 for as long as I can remember. Map or List, both respected the limit. How long have you been aware of this exception to the limit? – Mark Pond Aug 1 '16 at 19:03
  • 2
    @MarkPond The limit of 1000 is what I remember as well. I did find another similar question dating back to March 2016, so maybe it was intoduced in Summer '16. – Derek F Aug 1 '16 at 19:41
  • 4
    well, I'll be gobsmacked. Thanks Ishwar - shows that I'm not up to date with the details as described here. Nothing like having someone tell me I'm wrong to make me really learn something new :-) – cropredy Aug 2 '16 at 17:47
4

If you're just trying to generate a csv, add the readOnly attribute to your apex:page tag. From the documentation:

readOnly
Boolean
A Boolean value that enables read-only mode for a Visualforce page. In read-only mode, a page may not execute any DML operations, but the limit on the number of records retrieved is relaxed from 50,000 to 1 million rows. It also increases the number of items in a collection that can be handled by iteration components, from 1,000 to 10,000. If not specified, this value defaults to false.

I misunderstood your intention initially, and this obviously won't work if you want to insert records. Note in read-only mode, a page may not execute any DML operations.

If you still want to display all results, even when there are more than 1000, the simplest path forward is probably to serialize your records and use the jQuery DataTables plug-in. Specifically, look at the Javascript sourced data example.

To your controller you would simply need to add:

public String payload { get; private set; }

public PageReference readFile()
{
    // ...
    payload = JSON.serialize(uploadList);
}

Then your Javascript method to use oncomplete would be something like:

(function (w, $) {
    "use strict";
    w.renderTable = function () {
        var data = JSON.parse('{!JSENCODE(payload)}'),
            columns = [
                {"title": "Field 1 Label"},
                {"title": "Field 2 Label"} // etc.
            ];
        $('#tableDiv').DataTable({data: data, columns: columns});
    }
})(window, jQuery.noConflict());
| improve this answer | |
  • @Amar I thought you were generating a csv, hang on. – Adrian Larson Aug 1 '16 at 17:38
  • I think I made a mistake let me test once again – Learner Aug 1 '16 at 17:46
  • 1
    @Amar You can't do DML in a readonly page, obviously. Why do you need to display all the results? – Adrian Larson Aug 1 '16 at 17:48
2

The exceeds maximum size of 1000 error makes me think that this situation deals with the inherent limitation of the visualForce tags that iterate over collections (<apex:repeat>, <apex:pageBlockTable>, and <apex:dataTable>)

The only way that I know of to work around this limit is to start using pagination. The easiest way I know of to accomplish that is to use a StandardSetController link to relevant documentation

Controller:

// This is declared along with your other controller member variables
// (fileLines and uploadList)
public ApexPages.StandardSetController itemSetController;

public Pagereference ReadFile()
    {

        <existing code up to to the final return null omitted>

    // Begin by creating a new standardSetController, and passing in your List<Item__c>
    // It's important to note that this only works with sObjects.
    itemSetController = new ApexPages.StandardSetController(uploadList);

    // Here, we set the page size. This is the secret to not running over the 
    // 1000 record limit
    itemSetController.setPageSize(999);

    return null;

}


// This public getter changes to return the result from the set controller (rather than the uploadList itself).
// Without pagination controls, we'd always return the first page of results.
// We'll take care of the pagination controls in the VisualForce page itself
public List<Items__c> getuploadeditem()
{
    if (uploadlist!= NULL && uploadList.size() > 0)
        return itemSetController.getRecords();
    } else {
        return null;
    }
}

VisualForce:

<!-- In the visualforce page that I have using this pattern, 
I make the buttons part of the table header. 
These are outside of the header, as I don't know how 
this would interact with your existing table column headers -->

<!-- hasPrevious(), hasNext(), first(), previous(), next(), 
and last() are all methods provided by Salesforce.
By pressing the command button, these methods are called, which 
changes which rows are returned by getUploadedItem.
-->

<!-- The disabled attribute doesn't need to be set, but is a nice
 touch for users (and was already in my code, which I copy/pasted from) -->
<apex:outputPanel layout="block" style="text-align:center;">
    <apex:commandButton disabled="{!!itemSetController.hasPrevious}" value="First" action="{!itemSetController.first}" />
    <apex:commandButton disabled="{!!itemSetController.hasPrevious}" value="Prev" action="{!itemSetController.previous}" />
    <apex:commandButton disabled="{!!itemSetController.hasNext}" value="Next" action="{!itemSetController.next}" />
    <apex:commandButton disabled="{!!itemSetController.hasNext}" value="Last" action="{!itemSetController.last}" />
</apex:outputPanel>
<apex:pageblocktable value="{!uploadeditem}" var="item" rendered="{!NOT(ISNULL(uploadeditem))}">

      <apex:column headerValue="Number"> 
          <apex:outputText value="{!item.Item_Number__c}"/>
      </apex:column>


      <apex:column headerValue="Unit">
          <apex:outputField value="{!item.Unit__c}"/>
      </apex:column>

      <apex:column headerValue="Price">
          <apex:outputField value="{!item.price__C}"/>
      </apex:column>
 </apex:pageblocktable> 

I can't remember if re-rendering the part of the page that contains your pageblocktable is required or not.

| improve this answer | |
  • Lots of down votes flying around today. Someone seems to have a case of the Mondays. Well, I voted you up, I do think your approach is helpful. – Adrian Larson Aug 1 '16 at 23:22
  • 1
    @AdrianLarson Thanks! Gotta love those drive-by downvotes. – Derek F Aug 2 '16 at 0:12
  • 2
    the other workaround (relevant for repeat only) is lists of lists (e.g. controller builds up a list of 1000 elements, each with 1000 list elements = 1,000,000 elements. Of course, heap limits intervene here. Large, unlimited size CSV processing is hard to do in apex. – cropredy Aug 2 '16 at 2:06
  • @DerekF Thanks for your response, will try the logic you suggested – Learner Aug 2 '16 at 15:17

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.