5

I have a custom SObject named Book.

This custom Object has a few Fields:

  • Price
  • Pages
  • AmountInStock

How would I go about to get some methods onto Book, such as:

  • String toXML()
  • Boolean isAvailable()

I come from a strong MVC Pattern use in Rails so I am hoping I can get this set up instead of having to use static methods.

I have seen that some people use Wrapper Apex Classes like BookWrapper, but is that the best way to go?

  • By "Object", I believe you mean to say an "SObject"? The former is a class, the latter is a custom database table. – sfdcfox Nov 22 '13 at 13:19
  • Yes, a custom SObject. – Kevin Nov 22 '13 at 13:28
5

SObjects are generated by the system and rely on the underlying metadata (the model) that is exposed to the controller (Apex Code) and the view (Visualforce). Unfortunately, these objects are directly immutable. You can add neither methods nor properties to an SObject directly. This is why you will often see something akin to a "wrapper" class. This mechanism is necessary in order to add any functionality to the general SObject, such as being able to select records with a checkbox or various properties as in the original question (e.g. toXML). Usually, this is often the best way to go (but surely there are exceptions to the rule, right?).

  • 1
    Thank you. To me the wrapper class makes more sense than many other defined Apex Classes with static methods. Why not put all the additional needed business logic into Wrappers? – Kevin Nov 22 '13 at 13:49
  • Sometimes you need the logic in various places, in which case static methods are useful. Wrappers can also introduce problems with efficiency, such as querying for many related records at once, etc. Each has their place in the ecosystem, much like both plumbers and electricians are necessary in modern society, and you don't call your plumber for a light switch, nor the electrician for a clogged drain. – sfdcfox Nov 22 '13 at 16:53
1

You can add formula fields to your object which may be useful to you.

For example you could add a checkbox (aka boolean) formula field to your Book__c object which had some logic e.g.

IF (amountInStock__c > 0) && (discontinued__c == false)

You can then display this directly on page layouts, work with it in reports, code etc. I believe there are some considerations around performance in very high volume situations if you use these in queries.

  • Thank you. This would easily help for methods like isAvailable(), but would you generate a XML with a formula field? – Kevin Nov 22 '13 at 14:06
  • I don't think that would be practical or maintainable in most cases. I would probably have a helper class to do it at the point where the XML was being required. As an aside, for example you can use the standard REST api to retrieve any sObject and it will be represented in JSON. If your requirement is to call in and retrieve XML I would do it at that point in the code rather than implementing it on every single object I might want. – Doug B Nov 22 '13 at 14:11
0

Andrew Fawcett has a series of helpful articles on Apex enterprise patterns; the article on the Domain layer suggests a way of accomplishing what you are asking for. One nice thing about this pattern is that it helps you avoid writing code that exceeds governor limits. https://developer.salesforce.com/page/Apex_Enterprise_Patterns_-_Domain_Layer

Here's an example from the article

public class Opportunities extends SObjectDomain 
{

    // ... Constructor and overridden methods

    public void applyDiscount(Decimal discountPercentage, SObjectUnitOfWork uow)
    {
        // Calculate discount factor
        Decimal factor = Util.calculateDiscountFactor(discountPercentage);

        // Opportunity lines to apply discount to
        List<OpportunityLineItem> linesToApplyDiscount = new List<OpportunityLineItem>();

        // Apply discount 
        for(Opportunity opportunity&nbsp;: (List<Opportunity>) Records)
        {
            // Apply to the Opportunity Amount?
            if(opportunity.OpportunityLineItems.size()==0)
            {
                // Adjust the Amount on the Opportunity if no lines
                opportunity.Amount = opportunity.Amount * factor;
                uow.registerDirty(opportunity);
            }
            else
            {
                // Collect lines to apply discount to
                linesToApplyDiscount.addAll(opportunity.OpportunityLineItems);
            }
        }       

        // Apply discount to lines
        OpportunityLineItems lineItems = new OpportunityLineItems(linesToApplyDiscount);
        lineItems.applyDiscount(this, discountPercentage, uow);
    }
}

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.