Monday, November 18, 2013

SQL Restrict Number of Characters

I have used the 'left()' function to limit the results of a query in the past, but sometimes it does not work. The other function that can be used to limit the results of a query is substring, here is how it is used:

select Substring(notes,1,4000) as notes from history

Where the 1 is where you start and the 4000 is how many characters you want to pull in.

SUBSTRING ( expression ,start , length )

Tuesday, November 12, 2013

Override Button to Pre populate Fields

I found this blog post the other day and though it was very well written and very helpful!

http://raydehler.com/cloud/clod/salesforce-url-hacking-to-prepopulate-fields-on-a-standard-page-layout.html

More button code notes that are Task Button specific:

/00T/e?
who_id={!$User.Id}                                 // Set "Assigned to" to current user
&what_id={!ExpenseAccount__c.Id}   // "Related to" which object
&tsk1=Roger Wicki                                 // Override "Assigned to" with this name
&tsk2={!User.Name}                               // Related Contact's Name
&tsk3={!ExpenseAccount__c.Name}  // The Object's name
&tsk3_id=01ID0000000OiBz                // My custom object's ID
&tsk4={!(TODAY() + 7)}                          // Due Date
&tsk5=Print%20Expenses                     // Subject
// &save=1
// &save=x
&retURL=/{!ExpenseAccount__c.Id}
&cancelURL=/{!ExpenseAccount__c.Id}

For other objects you when using Google Chrome you can right click and "Inspect Element" to identify the field ID and use '&00Ni000000CKJg7' to preset a field value. This is most helpful for standard fields because you can get the same ID for custom fields by clicking on the field in the setup and pulling the ID from the URL.

Monday, October 28, 2013

Insert Merge Field Shortcut for Word (Conga Mail Merge)

Below are the shortcut keystrokes for entering a Mail Merge field into a word document.

ALT - I - F - M - M

From there you would just copy the Salesforce field name into the field name and click OK.

Tuesday, October 22, 2013

Link to local file in Salesforce

It seems there is no really easy way to link to a local file from Salesforce. After researching this topic in detail the blog post below provides the best solution to including this functionality in Salesforce. The biggest pain point in this solution for the user is that you can not click a button and be directed right to the document/folder. You have to copy the link stored in the formula field you create and copy that into a new browser window. The post takes you through the step by step process very well though.

http://salesforcetechie.wordpress.com/2013/07/19/linking-to-local-folders-in-salesforce-records/

Monday, October 21, 2013

Apex Trigger - Only Run at Point of Entry

You can put in a very simple condition that will prevent a trigger from running when bulk updates are made. This will only let the trigger run when one record is being edited at a time. This will exclude List View updates and data loader insert/updates:

if (Trigger.new.size() == 1) {

if (Trigger.old[0].isConverted == false){

}

}

Friday, October 18, 2013

Trigger Before and After Explanation

  • Before triggers can be used to update or validate record values before they are saved to the database.
  • After triggers can be used to access field values that are set by the database (such as a record's Id or lastUpdated field), and to affect changes in other records, such as logging into an audit table or firing asynchronous events with a queue.

http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_triggers.htm

Wednesday, October 2, 2013

Lead Conversion Trigger

Below is the syntax for a lead convert trigger.

trigger test on Lead (before update) {
 for(Lead lead:System.Trigger.new) {
  if (Lead.IsConverted)
  //do somethign here with converted leads
 }
}

Below is a more built out example from Jeff Douglas

http://blog.jeffdouglas.com/2009/02/13/enhancing-the-lead-convert-process-in-salesforce/

Friday, September 20, 2013

Indent keyboard shortcut in Gmail

I am always having to google this because I forget it, so I thought I would put it up here for reference...

  • Ctrl-] (Windows, Linux) or Command-] (Mac): Indent text (more)
  • Ctrl-[ (Windows, Linux) or Command-[ (Mac): Remove or lessend text indentation

Tuesday, September 3, 2013

Flags, Stoplights and Images in Salesforce Formula Fields

Below are the examples Salesforce gives you for creating formula fields that will display images such as flags, and stoplights. At the bottom is a link for the full knowledge article.

Flags for Case Priority

This formula displays a green, yellow, or red flag image to indicate case priority.
IMAGE( 
CASE( Priority, 
"Low", "/img/samples/flag_green.gif",
"Medium", "/img/samples/flag_yellow.gif",
"High", "/img/samples/flag_red.gif", 
"/s.gif"), 
"Priority Flag")

Color Squares for Case Age

This formula displays a 30 x 30 pixel image of a red, yellow, or green, depending on the value of a Case Age custom text field.
IF( Case_Age__c > 20, 
IMAGE("/img/samples/color_red.gif", "red", 30, 30),
IF( Case_Age__c > 10,
IMAGE("/img/samples/color_yellow.gif", "yellow", 30, 30),
IMAGE("/img/samples/color_green.gif", "green", 30, 30),
))

Traffic Lights for Status

This formula displays a green, yellow, or red traffic light images to indicate status, using a custom picklist field called Project Status. Use this formula in list views and reports to create a “Status Summary” dashboard view.
IMAGE( 
CASE(Project_Status__c, 
"Green", "/img/samples/light_green.gif",
"Yellow", "/img/samples/light_yellow.gif",
"Red", "/img/samples/light_red.gif", 
"/s.gif"), 
"status color")

Stars for Ratings

This formula displays a set of one to five stars to indicate a rating or score.
IMAGE( 
CASE(Rating__c, 
"1", "/img/samples/stars_100.gif",
"2", "/img/samples/stars_200.gif",
"3", "/img/samples/stars_300.gif", 
"4", "/img/samples/stars_400.gif", 
"5", "/img/samples/stars_500.gif", 
"/img/samples/stars_000.gif"), 
"rating")

Consumer Reports™—Style Colored Circles for Ratings

This formula displays a colored circle to indicate a rating on a scale of one to five, where solid red is one, half red is two, black outline is three, half black is four, and solid black is five.
IMAGE( 
CASE(Rating__c, 
"1", "/img/samples/rating1.gif",
"2", "/img/samples/rating2.gif",
"3", "/img/samples/rating3.gif", 
"4", "/img/samples/rating4.gif", 
"5", "/img/samples/rating5.gif", 
"/s.gif"), 
"rating") 

Horizontal Bars to Indicate Scoring

This formula displays a horizontal color bar (green on a white background) of a length that is proportional to a numeric score. In this example, the maximum length of the bar is 200 pixels.
IMAGE("/img/samples/color_green.gif", "green", 15, Industry_Score__c * 2) & 
IMAGE("/s.gif", "white", 15, 
200 - (Industry_Score__c * 2))


https://help.salesforce.com/apex/HTViewHelpDoc?id=useful_advanced_formulas.htm&language=en#ImageFormulasTitle



Wednesday, August 21, 2013

SqlError: FILESTREAM feature is disabled

I recently ran into this filestream SQL error when trying to restore a backup database. I have restored many databases in the past with no problem so I was a bit confused by the error. After googling it I found this post and it helped to fix the error!

http://brianseekford.com/index.php/2011/05/17/how-to-fix-sqlerror-filestream-feature-is-disabled/

Essentially you need to follow the steps below:


  1. Open SQL Configuration Manager and locate your database then right click on it and open up the properties
  2. Navigate to the FILESTREAM tab and check all the checkboxes then click apply
  3. Right click on your database again and restart it
  4. Close SQL Server Management Studio if it was opened then open it up again
  5. Run the query below
    1. EXEC sp_configure filestream_access_level, 2
    2. RECONFIGURE
  6. Close SQL Server Management Studio and reopen it
  7. Now you should be able to restore the database!



Monday, July 29, 2013

Eclipse Force.com IDE Issue Resolved

Over the years I have run into problem after problem with the Eclipse Force.com IDE. Once it is working I try not to touch anything to prevent it from breaking again!

I wanted to outline the issue I recently ran into and how I resolved it.

Whenever I tried to create a project or refresh an exiting project I was getting this error:

com.salesforce.ide.api.metadata.types.Metadata$JaxbAccessorF_fullName cannot be cast to com.sun.xml.bind.v2.runtime.reflect.Accessor

After researching it, primarily on the Developer discussion boards (this one specifically: http://boards.developerforce.com/t5/General-Development/Unable-to-refresh-resource/m-p/333759#M60381 ) I tried the solutions that were suggested in changing workspaces and running as an admin and neither of those worked. So I decided to downgrade the Java JRE from 7 to 6 and this worked!

I went here to download JRE 6 http://www.oracle.com/technetwork/java/javase/downloads/jre6-downloads-1637595.html then before I installed JRE 6 I uninstalled JRE 7 from the control panel.

To check what version of Java was currently running I went to the command prompt and typed in 'java -version' below is what output:

java version "1.7.0_05" ..... before I removed version 7

java version "1.6.0_34" .... after in uninstalled version 7 from the control panel

After that I started up the force.com IDE and everything worked perfectly! 

Tuesday, July 23, 2013

Using Apex Variables in SOQL and SOSL Queries (SOQL IN Clause)

I spent some time looking for this documentation around using the SOQL IN clause with a list and wanted to save it.

I basically want to run a SOQL query that is looking at a list of String values in the WHERE condition, like this:

// An IN-bind with an Id list. Note that a list of sObjects
// can also be used--the Ids of the objects are used for 
// the bind
Contact[] cc = [SELECT Id FROM Contact LIMIT 2];
Task[] tt = [SELECT Id FROM Task WHERE WhoId IN :cc];

// An IN-bind with a String list
String[] ss = new String[]{'a', 'b'};
Account[] aa = [SELECT Id FROM Account 
                WHERE AccountNumber IN :ss];


http://www.salesforce.com/us/developer/docs/apexcode/Content/langCon_apex_SOQL_variables.htm

Sunday, July 21, 2013

Basic For Loop

Below is a basic example of a for loop. I always seem to need to need this and forget the exact context.


trigger OpportunitySubmitForApproval on Opportunity (after update) {
 
 for (Integer i = 0; i < Trigger.new.size(); i++) {
 
  if (Trigger.old[i].Probability < 30 && Trigger.new[i].Probability >= 30) {
 
   // create the new approval request to submit
   Approval.ProcessSubmitRequest req = new Approval.ProcessSubmitRequest();
   req.setComments('Submitted for approval. Please approve.');
   req.setObjectId(Trigger.new[i].Id);
   // submit the approval request for processing
   Approval.ProcessResult result = Approval.process(req);
   // display if the reqeust was successful
   System.debug('Submitted for approval successfully: '+result.isSuccess());
 
  }
 
 }
 
}

Friday, May 24, 2013

Goldmine SQL Query to Filter on Date

Below is a basic query that will output the results of all ContHist records from 1/1/2009 and forward.

select * from CONTHIST where ondate > '2009-01-01'

Wednesday, May 22, 2013

Compare Two Blocks of Text

Ran across this nice little free online tool recently that compares 2 blocks of text. This is helpful if you are looking at code that could have been updated and pulling out those differences...

http://www.diffchecker.com

Friday, May 17, 2013

Mass Upload Pictures to Rich Text Field

There is a lot of confusing stuff out there about mass uploading pictures into a rich text field. Below is one thing I have found by testing actually works pretty well.

Process:

  1. Upload image as an attachment into Salesforce against the record the picture is being added to.
  2. Use that success file to create a new CSV file with the following attributes.
    1. The ID of the record having the image inserted
    2. A column that will have the following text
<img alt="User-added image" src="https://c.na14.content.force.com/servlet/servlet.FileDownload?file=00Pd0000003Uf0n"></img>

The 'User-added image' can be replaced with the name of the contact, or not replaced at all. Follow the steps below to fill out the hyperlink:

  1. Add an image to any record in your Salesforce org as an attachment
  2. Open up the attachment
  3. Right click on 'View file' and select 'Open link in a new tab' (this is the option for Chrome)
  4. Copy the url that appears on the new tab, this is the base for the image link
  5. It will take some excel manipulation, but you will need to use the success file for the attachment upload and replace the ID at the end with the ID of all attachments uploaded.
In the end you will only need 2 columns in the file that is uploaded. One being the ID of the record that is receiving the picture, two being the img url from above.


Tuesday, May 14, 2013

Importing Zip Codes with a Leading Zero into Salesforce.com

When importing Zip Codes into Salesforce because the file must be in CSV format you can run into problems you didnt know were there. For example when you open up a data file in CSV format if there are any Zip codes with leading zeroes like 01752 they will appear with the leading zero chopped off and will display like 1752.

You can follow these steps below to be sure to load those leading zeroes.

1. Select the entire Zip Code column from within Excel. 

2. Select the menu option Format -> Cells...

3. Select the Number tab, and click on the category called "Special".

4. You can then select the type Zip Code or Zip Code + 4, and then click OK.

Be sure to save the changes to your .CSV file. 

NOTE: If you reopen the saved .CSV file in Excel, the formatting is not preserved. Opening in Notepad preserves the formatting. Save the formatting of the zip code for your last step when importing records. If you do not reopen the .CSV file in Excel before importing, the zip codes are imported with the appropriate leading zeroes.




These steps came from the Salesforce custom community:

https://success.salesforce.com/questionDetail?qId=a1X30000000HZDMEA4

Monday, May 13, 2013

How to Quickly Check the Old Value in an APEX Trigger

Using the Old Map context variable in a trigger can quickly look back at the old value of a field in a trigger. This can be helpful when you need to write a trigger that is checking to see if a value has been changed...

for ( lead l_new: Trigger.new ){

     if ( l_new.Status != Trigger.oldMap.get ( l_new.id ).Status ) {
   
     }

}



Friday, May 10, 2013

Automating Salesforce Approval Processes with Apex Triggers

Ran across this the other day and wanted to re-post it, looks easy enough to implement...

http://blog.jeffdouglas.com/2010/01/04/automating-salesforce-approval-processes-with-apex-triggers/



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
trigger OpportunitySubmitForApproval on Opportunity (after update) {
 
 for (Integer i = 0; i < Trigger.new.size(); i++) {
 
  if (Trigger.old[i].Probability < 30 && Trigger.new[i].Probability >= 30) {
 
   // create the new approval request to submit
   Approval.ProcessSubmitRequest req = new Approval.ProcessSubmitRequest();
   req.setComments('Submitted for approval. Please approve.');
   req.setObjectId(Trigger.new[i].Id);
   // submit the approval request for processing
   Approval.ProcessResult result = Approval.process(req);
   // display if the reqeust was successful
   System.debug('Submitted for approval successfully: '+result.isSuccess());
 
  }
 
 }
 
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@isTest
private class TestOpportunitySubmitForApproval {
 
    static testMethod void testApprovalSuccess() {
 
        Opportunity opp = new Opportunity();
        opp.Name = 'Test Opp';
        opp.Amount = 100;
        opp.CloseDate = Date.today();
        opp.Probability = 10;
        opp.StageName = 'Prospecting';
        // insert the new opp
        insert opp;
        // change the probability of the opp so the trigger submits it for approval
 opp.Probability = 40;
 // update the opp which should submit it for approval
 update opp;
 
        // ensure that the opp was submitted for approval
        List<ProcessInstance> processInstances = [select Id, Status from ProcessInstance where TargetObjectId = :opp.id];
 System.assertEquals(processInstances.size(),1);
 
    }
 
}

Monday, May 6, 2013

White List IP Address for Data Loader access with no Security Token

Just found out that if you white list your IP address in a Salesforce org you do not need a security token to use APEX Data Loader. If a login is shared and the email address associated with the login is someone hard to reach, you can just do this and bypass getting a security token to load data!

Setup > Your Name > Security Controls > Network Access > New

Make the Start and End IP address your personal PC's IP address.

Note: You can do a google search of 'Whats my ip' to get your computer's ip address.

Once this is done when you login to data loader still use your username, but rather than using passwordSECURITYTOKEN as the password, all you need is the password.

Wednesday, April 10, 2013

Strip HTML Tags in SQL

At the bottom are a couple links that helped me to strip HTML tags from columns in SQL.

First create the UDF using the following code:


CREATE FUNCTION [dbo].[udf_StripHTML] (@HTMLText VARCHAR(MAX))
RETURNS VARCHAR(MAX) AS
BEGIN
    DECLARE @Start INT
    DECLARE @End INT
    DECLARE @Length INT
    SET @Start = CHARINDEX('<',@HTMLText)
    SET @End = CHARINDEX('>',@HTMLText,CHARINDEX('<',@HTMLText))
    SET @Length = (@End - @Start) + 1
    WHILE @Start > 0 AND @End > 0 AND @Length > 0
    BEGIN
        SET @HTMLText = STUFF(@HTMLText,@Start,@Length,'')
        SET @Start = CHARINDEX('<',@HTMLText)
        SET @End = CHARINDEX('>',@HTMLText,CHARINDEX('<',@HTMLText))
        SET @Length = (@End - @Start) + 1
    END
    RETURN LTRIM(RTRIM(@HTMLText))
END
GO


Then to run the UDF you simply would include it in the query like this:

select USERID, ACCOUNTNO, RECTYPE, ONDATE, ONTIME, REF, dbo.udf_StripHTML(NOTES), LINKRECID, recid, RFC822 from HISTandMAILtrimmed


http://stackoverflow.com/questions/457701/best-way-to-strip-html-tags-from-a-string-in-sql-server

http://ask.sqlservercentral.com/questions/2022/how-to-execute-sql-udf-function.html

Tuesday, March 5, 2013

Try Catch Statement Used When Inserting Records in APEX


try{
    insert pcList;
}
catch(DmlException e){
     System.debug('AgencyCommissionTrigger: DML Exception: Error during AgencyCommissionTrigger updates in the AgencyCommissionTrigger trigger.');
     for (Integer i = 0; i < e.getNumDml(); i++) {
          System.debug(e.getDmlMessage(i));
     }//end for
}//end catch

Tuesday, February 26, 2013

Query for Exporting from Goldmine CAL table to Excel

Below are two queries that can be used to extract from the CAL table in a Goldmine SQL database.

If the Notes and RFC822 fields are in a Blob format where their values are not standard text use this:


Select
c.USERID, c.ACCOUNTNO, c.RECTYPE, c.ONDATE, c.[ONTIME], c.[DURATION], c.REF as [Subject History - REF],
c.LINKRECID, c.recid,
CAST(CAST(c.NOTES AS varbinary(4000)) AS varchar(4000)) AS NOTES,
CAST(CAST(m.RFC822 AS varbinary(4000)) AS varchar(4000)) AS RFC822

From CAL as c
Left Join MAILBOX as m
ON c.LINKRECID = m.recid


If the Notes and RFC822 fields are in a standard text format you can use this query:



set textsize 4000

Select
c.USERID, c.ACCOUNTNO, c.RECTYPE, c.ONDATE, c.[ONTIME], c.[DURATION], c.REF as [Subject History - REF],
c.LINKRECID, c.recid, c.NOTES, m.RFC822

From CAL as c
Left Join MAILBOX as m
ON c.LINKRECID = m.recid

Wednesday, February 6, 2013

Salesforce.com Professional Edition Pain Points


The most common editions of Salesforce.com that businesses will sign up for are Professional Edition and Enterprise Edition. A quick way to tell what version you are on is when using google chrome as your browser if you go to the home tab in Salesforce, the chrome tab will say "Salesforce.com - Professional Edition" or "Salesforce.com - Enterprise Edition".

There are a number of items that are sorely missed when going from Enterprise to Professsional Edition, below is a list of items missing from Professional Edition that can cause some headaches.

  • Workflow Rules
  • Apex Triggers
  • Apex Classes
  • API
  • Joined Reports
  • Custom Profiles
  • Record Types
  • Grant Login Access


You can see a more detailed list of what is offered in all of Salesforce's editions here:
http://www2.sfdcstatic.com/assets/pdf/datasheets/DS_SalesCloud_EdCompare.pdf

Monday, February 4, 2013

Pull Record Type ID in Apex


This is just a quick query that grabs the record type id and assigns it to a string. I am always needing this so decided to put it up on the blog for reference. You need something like this when specifying a record type because if you would hard code the id into the trigger/class in production it would fail because everything has a different id from Sandbox to Production.

RecordType r = [select id from RecordType where name = ‘Account Recortype’ AND SobjectType = 'Account'];
String AcctRecordtypeID= r.id;

So the string AcctRecordtypeID will now have the record id of the record type pacesetter.

If there are multiple record types out there with the same name associated to different object, you can just adjust the where statement to be more specific about where to pull the RecordType from.

Alternatively the same query could be used with a list. This will prevent an error in the event that there is no recordtype with the name specified.

List<RecordType> recType = [select id from RecordType where name = 'Pharma' AND sobjecttype = 'Account' AND IsActive = TRUE limit 1];

if(!recType.isempty()){
String PharmaRecordTypeID = rectype[0].id;

}

Friday, February 1, 2013

Map Described

I have recently begun to understand the value of Maps when writing Apex triggers and classes, they can be very powerful. The most common Map used is the 'Map <ID, sObject>' this means that the Key of the Map is the ID and the value is the object related to the ID.

Typically you will see it initiated in this way:

Map<ID,sObject> sObMap = new Map<ID,sObject>([SELECT *fields* FROM sObject WHERE *conditions*]);

This is how I used it in a recent bit of code I wrote. This trigger copies the owner of the Account related to a case down to the case record on a custom field.




trigger CaseBeforeInsertTrigger on Case (before insert) {

    Set<Id> accountIds = new Set<Id>(); //set to hold list of Accounts

    for (Case c : Trigger.new) { //loop through all cases and pull the Account ID into the set above
        if(c.AccountId != null) {
        accountIds.add(c.AccountId);
        }      
    }
 
    Map<ID, Account> acct = new Map<ID, Account>([select id, ownerid from Account where id = : AccountIds]); //create a map where the ID is the Key and the Value is the sObject (Account)

    if(acct.size() > 0) {
        for(Case c: Trigger.new) { //if there are values in the map, loop through the new cases
      if (c.AccountId != null){
     
          Account acctUpdate= acct.get(c.AccountID); //look back into the map and using the Account ID grab the Account sObject
          c.Account_Owner__c = acctUpdate.OwnerId;
     
      }
        }
    }
}

Thursday, January 24, 2013

Adding an Activity to a Chatter Feed Using a Trigger

I have had many requests for a trigger like this over time and Kevin Swiggum had a post back in 2010 with a simple to implement solution for this request, the link is below.

http://www.radialweb.com/2010/09/adding-activity-to-a-chatter-feed-using-triggers/


Below is a copy of the code Kevin posted:

trigger ChatterActivity on Task (after insert, after update) {

    List<FeedItem> feedItems = new List<FeedItem>();

    //We want to show the User name as assignedTo. The only way to get to that is by querying the user table.
    Set<ID> ownerIds = new Set<ID>();
    for (Task t : Trigger.new) {
        ownerIds.add(t.ownerId);
    }
    Map<ID,User> userMap = new Map<ID,User>([SELECT ID, Name FROM User WHERE ID IN :ownerIds]); //This is our user map

    //Now loop though the new/updated tasks and create the feed posts
    for (Task t : Trigger.new) {
        if (t.WhatId != null) {
            FeedItem fitem = new FeedItem();
            fitem.type = 'LinkPost';
            fitem.ParentId = t.WhatId;
            fitem.LinkUrl = '/' + t.id; //This is the url to take the user to the activity
            fitem.Title = 'View';  //This is the title that displays for the LinkUrl

            //Get the user by checking the userMap we created earlier
            User assignedTo = userMap.get(t.ownerId);

            fitem.Body = ((Trigger.isInsert) ? 'New' : 'Updated') + ' Activity ' + ((t.ActivityDate != null) ? t.ActivityDate.format() :'')
                        + '\nAssigned To: ' + ((assignedTo != null) ? assignedTo.name : 'Unknown')
                        + '\nSubject: ' + t.Subject
                        + '\nStatus: ' + t.Status;

            feedItems.add(fitem);
        }
    }

    //Save the FeedItems all at once.
    if (feedItems.size() > 0) {
        Database.insert(feedItems,false); //notice the false value. This will allow some to fail if Chatter isn't available on that object
    }
}


And here is the test class associated

public with sharing class ChatterUnitTests {

    /*
    *    Test the ChatterActivity trigger which inserts chatter feed posts whenever a task is inserted on the parent object
    */
    public static testMethod void testChatterActivity() {
        //create the test account
        Account a = new Account(name='Test Account');
        insert a;

        //create a task on that account
        Task t = new Task(whatId=a.id);
        t.Subject = 'This is a test activity for chatter';
        t.ActivityDate = System.today();
        t.Status = 'In Progress';
        t.Description = 'Hello, this will be chattered';

        insert t;

        //Make sure Account has the feed enabled. If it does, make sure the chatter feed post is there
        Schema.DescribeSObjectResult r = Account.SObjectType.getDescribe();
        if (r.isFeedEnabled()) {
            List<AccountFeed> posts = [SELECT Id, Type FROM AccountFeed WHERE ParentId = :a.id];
            System.assertEquals(1, posts.size());
        }
    }
}







Wednesday, January 16, 2013

Bulkify Apex Triggers

This is something that has been harped on in every Apex class I have taken and it finally clicked with me! This is probably much more clearly explained in the link below from developer.force.com but I want to document it here for my own knowledge.

http://wiki.developerforce.com/page/Best_Practice:_Bulkify_Your_Code

  • Create a SET before entering trigger.new that will hold the ID of all SObjects being updated or looped through
  • Pull a list of the IDs of the SObjects that need to be updated when looping through trigger.new and add them to the SET defined above
  • If that SET contains items then create a list of SObjects and use 1 SOQL query to populate the entire list
  • Now you can loop through the entire list of SObjects and make updates from there...

Below is an example of this in action:

if(trigger.isBefore){
//Set to hold the list of Contract Id's that will be queried for the associated Account 
Set<String> ContractIds = new Set<String>();
//loop through all Agency Commission Records and add the Id of the Contract to the ContractIds Set
for(Agency_Commission__c ac : trigger.new){
if(ac.Contract__c != null){
ContractIds.add(ac.Contract__c);
}
}
if(!ContractIds.isEmpty()){
//Use a single query to pull a list of Contract SObjects
List<Asset_C__c> contractList = [select id, Account__c from Asset_C__c where id =: ContractIds];

//Map to hold the Contract ID as the Primary Key and the Account ID as the Key Value
Map<string, string> ContractAndAccount = new Map<string, string>();
//Loop through the List of Contracts and add the Contract ID and Account ID to the map
for(Asset_C__c c1 : contractList){
if(c1.Account__c != null){
ContractAndAccount.put(c1.id, c1.Account__c);
}
}
if(!ContractAndAccount.isEmpty()){
//Loop through the original Agency commission values and assign the Account based on the ContractAndAccount Map
for(Agency_Commission__c acUpdate : trigger.new){
//retrieve the Account from the ContractAndAccount Map and assign it to a string value
String acctForContract = ContractAndAccount.get(acUpdate.Contract__c);
acUpdate.Client__c = acctForContract;
}
}
}
}