+ Start a Discussion
jygjyg 

Not in constructor: "DML currently not allowed", why?

Here's a snippet from my singleton class.  Its basically serves an Order__c record to the client controllers that need it.  Controller will call "OrderService.getInstance()...".  Initial instantiation is guaranteed to have an Order__c record that is saved in Salesforce.  However, in the *not-a-constructor*  static getInstance() method I get that darn "System.LimitExpcetion: DML currently not allowed" error.  Any ideas?   FWIW, all my Components have allowDML="true".

 

thanks,

 

Jason Gabler

 

public class OrderService {

 private static OrderService self;
 private final static String orderIdCookieName = 'someCompanyOrderId';
 private Order__c order;

 private OrderService() {
   Cookie c = ApexPages.currentPage().getCookies().get(orderIdCookieName);
   Id orderId = (c == null) ? null : c.getValue();
   if (orderId != null) {
     this.retrieveOrder(orderId);  // does nothing if a record cannot be found in Salesforce
   }
   if (this.order == null) {
     this.order = new Order__c();  // just make a new record, can't to DML here so don't try to insert
   }
 }

// Controllers will call OrderService.getInstance() to get the singleton isntance of this service public static OrderService getInstance() { if (self == null) { self = new OrderService(); // create the singleton, we can see from above we are guarnateed upsert self.order; // **** "DML currently not allow", why not?! } return self; } ... }

 

 

 

 

Best Answer chosen by Admin (Salesforce Developers) 
sfdcfoxsfdcfox

I agree. I can't tell you how much trouble that's put our project in. We use custom settings extensively for a variety of settings, pseudo-permissions, and so on. Sometimes there's a perfectly good use for DML in a getter, but we're still not allowed to do it. Merry Christmas/Happy Hanukkah/Happy Hollidays/etc :p Glad you found the problem.

All Answers

sfdcfoxsfdcfox

If getInstance() is called from a constructor (e.g. a VF page controller), you'll get this error (upsert is called while still in a constructor). You can use an "action" function on the page if you need to call this function:

 

<apex:page controller="SomeController" action="{!initOrder}">
  <!-- page code here -->
</apex:page>

 

public with sharing class SomeController {
  OrderService orderServiceController;

  public void initOrder() {
     OrderServiceController = OrderService.getInstance();
  }
}

 

jygjyg

Hmm... I pretty much explained right in the subject/title of the original post that this is not being called from a constructor.  And you can clearly see in the code that its not being called in a constructor.    I have no need to call this from a VF action.

 

I want to know why I am getting this error.  Again... nothing to do with constructors.  

 

The only thing I can think of is that there is some undocument restriction on executing DML statements  within static methods.  But I see absolutey no documentation or board discussion that makes this claim.

 

jason

sfdcfoxsfdcfox

Double-check your debug logs, starting from the line that reads:

 

METHOD_ENTRY|className.className

All the way to:

 

METHOD_EXIT|className

Must not contain any DML operations (and ergo must not contain DML statements). Thinking about it, I believe it is also an error if you use DML in a getter function as well. DML is allowed only during setter methods and action methods.

jygjyg

A mix of things you said got me to the answer, and the answer is irritating.

 

I looked through the debug logs closer, as you suggested, following method entries and exists.  A constructor is not the issue, but as I found the issue, I though of your comment about getters.  I knew you can't to DML in getters, but what's been distracting me is that it doesn't matter how deep the DML is in the call stack, you still can't do it.  The DML is called, eventually, from within a getter.  At least this explains why this worked fine in my unit tests but not in my controller tests.

 

What irritates me, other than my initial shortsightedness, is that do use something as simple and elegant as a singleton pattern in Apex you have to do those dirty little tricks.  

 

Oh, and thanks for the help :)

 

jason

sfdcfoxsfdcfox

I agree. I can't tell you how much trouble that's put our project in. We use custom settings extensively for a variety of settings, pseudo-permissions, and so on. Sometimes there's a perfectly good use for DML in a getter, but we're still not allowed to do it. Merry Christmas/Happy Hanukkah/Happy Hollidays/etc :p Glad you found the problem.

This was selected as the best answer