function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
ptepperptepper 

System.Exception: DML currently not allowed ... External entry point

Hello,

I'm trying to create a delete function for a custom object. In my Visualforce code, there's a link that goes to a new page with an object ID query parameter. The controller on that next page gets the id and tries to delete the object. I'm getting this error:

System.Exception: DML currently not allowed

Class.MyDeleteController.<init>: line .., column ..
External entry point

Anyone know why I might be getting this error and how to make this work? I would think that executing a delete function in Apex from Visualforce would be something pretty basic. I've tried executing the function multiple ways, by Id and with the object itself, with code like this:

Id id = ApexPages.currentPage().getParameters().get('id');
delete id;


(Database.delete(id) doesn't work either, same error)

MyObject obj = [select id, Name FROM MyObject__c WHERE id = :id];
delete obj;


(Database.delete(obj) doesn't work either, same error)
 

-paul
Best Answer chosen by Admin (Salesforce Developers) 
dchasmandchasman
Take a look at the doc and examples for apex:commandLink and apex:commandButton - what you are trying to do is a very common and easy to implement using these components and their built in action binding and partial page update support. The is definitely no need for a second page - the way we do deletes in salesforce today is biazarre to say the least and will be changing over time - please do not emulate that anti pattern. Also, any time you think you might want to use apex:actionFunction step back and look to see if we have a higher level way to accomplish your goal. actionFunction comes in handy when you want to attach a client side behavior/event with a server side action and the event is not on a component or there is not already a built in direct wiring like we have with <apex:commandLink action> (basically wires up the equivalent of apex:actionFunction that will fire when the link is clicked).

All Answers

Ron HessRon Hess
if you are seeing message, i think you are performing the work in a controller constructor, is that correct?

Try creating an action method, and invoke that from the action param on the page tag instead, that should happen after the controller constructor, and should allow a delete.

action
The action method invoked when this page is first requested by the server. Use merge-field syntax to reference the method. For example, action="{!init}" references the init() method in the controller. If an action is not specified, the page simply refreshes.

something like this

<apex:page  action="{!deleteMyRecord}" ... >
</apex:page>
ptepperptepper
Ron,

That worked perfectly, thanks!

My current setup emulates an object view list/table, where each row in the table has an object with a 'delete' link. Each delete link goes to another visualforce page which handles the delete. The handler page executes the delete function and then does a Javascript redirect back to the original page (where the delete link was). It seemed like this is sort of how the normal salesforce delete function works, with delete links linking to a page like this:

https://na5.salesforce.com/setup/own/deleteredirect.jsp?delID=xxxxxxxxx&retURL=%2Fa0A%3Ffcf%xxxxxxx%26page%3D1%26rolodexIndex%3D-1

However, it seems like it makes more sense to use AJAX to do something like this and then rerender the list/table, instead of doing the action through an intermediate page. I tried this using the apex:actionFunction component, but was never able to get it working. From what I described, does it sound like something like the following could also do the job?
<apex:actionFunction action="{!myDelete}" name="myDeleteJS" rerender="objectList" >
<apex:param name="id" assignTo="{!objectId} value="" />
</apex:actionFunction>

<a onclick="return confirmDelete();" href="javascript&colon;myDeleteJS({!object.id})>Del</a>


thanks again,
-paul


Message Edited by ptepper on 07-23-2008 03:09 PM
dchasmandchasman
Take a look at the doc and examples for apex:commandLink and apex:commandButton - what you are trying to do is a very common and easy to implement using these components and their built in action binding and partial page update support. The is definitely no need for a second page - the way we do deletes in salesforce today is biazarre to say the least and will be changing over time - please do not emulate that anti pattern. Also, any time you think you might want to use apex:actionFunction step back and look to see if we have a higher level way to accomplish your goal. actionFunction comes in handy when you want to attach a client side behavior/event with a server side action and the event is not on a component or there is not already a built in direct wiring like we have with <apex:commandLink action> (basically wires up the equivalent of apex:actionFunction that will fire when the link is clicked).
This was selected as the best answer
sfdcfoxsfdcfox
For anyone who might find this post after all this time looking for a solution to this problem, I might add that the solution notes that Salesforce uses a "second page" for deletion redirects. This is done in order not create a "location" entry in the user's browser. This prevents awkward moments when the user is pressing "back" to get to a record and accidentally reperforms an action (i.e. effectively saving an older version of a record over a newer version, re-deleting a record that was deleted and then restored, emptying the Recycle Bin by accident, thus destroying records, and other sorts of unintentional mayhem). Ajax pages don't need this sort of protection, so you wouldn't ordinarily use a two-page method, since that would, in all actuality, be redundant and useless.
SsuazoSsuazo

Can anybody give me a clear explanation on the exact meaning of an External Entry Point Error and what causes it? Also, if possible how to fix it as well. Any insight will help .... Thanks in adavance

SsuazoSsuazo

 

So i executed the code below and im gettin an external entry point error and i have no clue why. Can anyone help, Thanks

 

public class AccountDuplicateTriggerTests{
    static testMethod void AccountDuplicateTrigger() {
       
      // First make sure there are no leads already in the system 
   
      // that have the email addresses used for testing 
     
    
     
      Set<String> testBillingPostalCode = new Set<String>();
      testBillingPostalCode.add('10456');
      testBillingPostalCode.add('20457');
      testBillingPostalCode.add('30458');
      testBillingPostalCode.add('40459');
      testBillingPostalCode.add('50451');

      Set<String> testBillingCity = new Set<String>();
      testBillingCity.add('Bronx');
      testBillingCity.add('Queens');
      testBillingCity.add('Manhattan');
      testBillingCity.add('Staten Island');
      testBillingCity.add('Long Island');
     
      Set<String> testBillingStreet = new Set<String>();
      testBillingStreet.add('1 Franklin Ave');
      testBillingStreet.add('2 Franklin Ave');
      testBillingStreet.add('3 Franklin Ave');
      testBillingStreet.add('4 Franklin Ave');
      testBillingStreet.add('5 Franklin Ave');
     
      Set<String> testBillingState = new Set<String>();
      testBillingState.add('NY');
      testBillingState.add('PA');
      testBillingState.add('MD');
      testBillingState.add('NV');
      testBillingState.add('AZ');

     
      System.assert([SELECT count() FROM Account
                     WHERE BillingStreet IN :testBillingStreet AND BillingCity IN :testBillingCity AND
                     BillingState IN :testBillingState AND BillingPostalCode IN :testBillingPostalCode] == 0);
       
      // Seed the database with some leads, and make sure they can 
   
      // be bulk inserted successfully. 
   
      Account account1 = new Account(Name='Test1', BillingStreet='1 Franklin Ave', BillingCity='Bronx', BillingState='NY',
      BillingPostalCode='10456');
      Account account2 = new Account(Name='Test2', BillingStreet='2 Franklin Ave', BillingCity='Queens', BillingState='PA',
      BillingPostalCode='20457');
      Account account3 = new Account(Name='Test3', BillingStreet='3 Franklin Ave', BillingCity='Manhattan', BillingState='MD',
      BillingPostalCode='30458');
      Account[] accounts = new Account[] {account1, account2, account3};
      insert accounts;
       
      // Now make sure that some of these leads can be changed and 
   
      // then bulk updated successfully. Note that lead1 is not 
   
      // being changed, but is still being passed to the update 
   
      // call. This should be OK. 
   
      account2.BillingStreet = '2 Franklin Ave';
      account3.BillingStreet = '3 Franklin Ave';  
     
      account2.BillingCity = 'Queens';
      account3.BillingCity = 'Manhattan';
     
      account2.BillingState = 'PA';
      account3.BillingState = 'MD';
     
      account2.BillingPostalCode='20457';
      account3.BillingPostalCode='30458';
     
      update accounts;
       
      // Make sure that single row lead duplication prevention works 
   
      // on insert. 
   
      Account dup1 = new Account(Name='Test1Dup',
                           BillingStreet = '2 Franklin Ave', BillingCity = 'Queens', BillingState = 'PA',
                           BillingPostalCode='20457' );                        
            // Make sure that single row lead duplication prevention works 
   
      // on update. 
     
         try {
         insert dup1;
         System.assert(false);
      } catch (DmlException e) {
         System.assert(e.getNumDml() == 1);
         System.assert(e.getDmlIndex(0) == 0);
         System.assert(e.getDmlFields(0).size() == 1);
         System.assert(e.getDmlMessage(0).indexOf(
            'A lead with this email address already exists.') > -1);
      }

   
      dup1 = new Account(Id = account1.Id, Name='Test1Dup',
                      BillingStreet='1 Franklin Ave', BillingCity = 'Bronx', BillingState = 'NY',
                      BillingPostalCode='10456');
                     
     try {
         update dup1;
         System.assert(false);
      } catch (DmlException e) {
         System.assert(e.getNumDml() == 1);
         System.assert(e.getDmlIndex(0) == 0);
         System.assert(e.getDmlFields(0).size() == 1);
         System.assert(e.getDmlMessage(0).indexOf(
            'A lead with this email address already exists.') > -1);
        }

                     
                    
                  
        
      // Make sure that bulk lead duplication prevention works on 
   
      // insert. Note that the first item being inserted is fine, 
   
      // but the second and third items are duplicates. Note also 
   
      // that since at least one record insert fails, the entire 
   
      // transaction will be rolled back. 
   
      dup1 = new Account(Name='Test1Dup', BillingStreet='1 Franklin Ave', BillingCity = 'Bronx', BillingState = 'NY');
                    
      Account dup2 = new Account(Name='Test2Dup',
                           BillingStreet = '2 Franklin Ave', BillingCity = 'Queens', BillingState = 'PA',
                           BillingPostalCode='20457');
      Account dup3 = new Account(Name='Test3Dup',
                           BillingStreet = '3 Franklin Ave', BillingCity = 'Manhattan', BillingState = 'MD',
                           BillingPostalCode='30458');     
                           Account[] dups = new Account[] {dup1, dup2, dup3};
                          
                      
 
   
      // Make sure that bulk lead duplication prevention works on 
   
      // update. Note that the first item being updated is fine, 
   
      // because the email address is new, and the second item is 
   
      // also fine, but in this case it's because the email 
   
      // address doesn't change. The third case is flagged as an 
   
      // error because it is a duplicate of the email address of the 
   
      // first lead's value in the database, even though that value 
   
      // is changing in this same update call. It would be an 
   
      // interesting exercise to rewrite the trigger to allow this 
   
      // case. Note also that since at least one record update 
   
      // fails, the entire transaction will be rolled back. 
   
      dup1 = new Account(Id=account1.Id, BillingStreet = '4 Franklin Ave', BillingCity = 'Staten Island', BillingState = 'NV',
      BillingPostalCode='40459');
      dup2 = new Account(Id=account2.Id, BillingStreet = '2 Franklin Ave', BillingCity = 'Queens',BillingState = 'PA',
      BillingPostalCode='20457');
      dup3 = new Account(Id=account3.Id, BillingStreet = '3 Franklin Ave', BillingCity = 'Manhattan',BillingState = 'MD',
      BillingPostalCode='30458');

      dups = new Account[] {dup1, dup2, dup3};
            
 

      // Make sure that duplicates in the submission are caught when 
   
      // inserting leads. Note that this test also catches an 
   
      // attempt to insert a lead where there is an existing 
   
      // duplicate. 
   
      dup1 = new Account(Id=account1.Id, BillingStreet = '4 Franklin Ave', BillingCity = 'Staten Island', BillingState = 'NV',
      BillingPostalCode='40459');
      dup2 = new Account(Id=account2.Id, BillingStreet = '3 Franklin Ave', BillingCity = 'Manhattan', BillingState = 'MD',
      BillingPostalCode='30458');
      dup3 = new Account(Id=account3.Id, BillingStreet = '3 Franklin Ave', BillingCity = 'Manhattan', BillingState = 'MD',
      BillingPostalCode='30458');
            dups = new Account[] {dup1, dup2, dup3};
             
      // Make sure that duplicates in the submission are caught when 
   
      // updating leads. Note that this test also catches an attempt 
   
      // to update a lead where there is an existing duplicate. 
   
      dup1 = new Account(Id=account1.Id, BillingStreet = '4 Franklin Ave', BillingCity = 'Staten Island', BillingState = 'NV', BillingPostalCode='40459');
      dup2 = new Account(Id=account2.Id, BillingStreet = '4 Franklin Ave', BillingCity = 'Staten Island', BillingState = 'NV', BillingPostalCode='40459');
      dup3 = new Account(Id=account3.Id, BillingStreet = '2 Franklin Ave', BillingCity = 'Queens', BillingState = 'PA', BillingPostalCode='20457');
      dups = new Account[] {dup1, dup2, dup3};
         }
}