• sparktest
  • NEWBIE
  • 0 Points
  • Member since 2008

  • Chatter
    Feed
  • 0
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 7
    Questions
  • 31
    Replies

 

I have a trigger that launches a delete on a child/detail object based on an appropriate update to the master object.  This will often entail more than 100 records hence the use of the @future method. 

 

The tests are failing on the path that uses the @future method.

 

Any Help?

 

thanks,

 

has anyone tried to set this up so they can only access certain objects through it?

 

Does anyone have any examples of doing this, or can they point to a good example?  I am trying to use a bulk List insert to load a child object per a specific update/insert to the parent object.  I am presently successful, so long as there are 100 records or less.  If I go over 100 records, it gives me a DML error, though I am using the bulk insert as told to.

 

I can find update examples that are similar, but so far nothing that matches what I am trying to do....which doesn't seem to be anything that would be odd.  Mainly I just want to confirm that what I am trying to do is even possible, so if not, I can look into something else.

 

Can I load/update more than 100 records on a child object based on an update/insert of a parent Object?

 

Thank You For ANY help on this.

 

 

I am getting the below error on the myMethod line below.  for the life of me I cannot figure out why....obviously the semi-colon is there.

 

Any help from another pair of eyes would be great!

 

Thanks,


Save error: expecting a semi-colon, found '' SiteLeaseCumCostUpdate/src/classes SiteLeaseFncTblClass.cls line 182

 

 

if (j > 100)

{

myMethod(List<String> ListLeaseID, List<Date> ListDate, List<Decimal> ListCumDefRent, List<Decimal> ListRent, List<Integer> ListTerm);

}

else if (j <= 100)

{

insert followuprecords;

}

else

{

}

 
I have two custom objects, one is the master and one child.  When I click on Edit on a record of the child object in the related list of the master object, make a change and click save, an after update trigger for the master object fires.  Is this a bug?  I am not updating anything on the master object but it is acting like I am......
 
Any thoughts on this?
 
Thanks,
I have an after update trigger that fires the below class.  I am creating a number of related records depending on values in the master object.  I have seen some of the examples of @future and I am not sure if I can even do this. 
 
Is there a better way? I am bumping up against the limit and I was hoping @future would take care of it, but I get an error of
 
"Save error: Unsupported parameter type LIST:SOBJECT:Site_Lease_Contract__c SiteLeaseCumCostUpdate/src/classes SiteLeaseFncTblClass.cls line 4"
 
When I try to save as below (minus the '@future' is works fine)
 
 
Code:
public class SiteLeaseFncTblClass 
{
 @future
 public static void SiteLeaseFncTblTrigger(Site_Lease_Contract__c[] newSiteLeaseFncTbl) 
 {
  for (Integer i = 0; i < Trigger.new.size(); i++) {
   
      List<SiteFnc__c> followuprecords = new List<SiteFnc__c>();
      
       Boolean GT = newSiteLeaseFncTbl[i].Generate_Table__c;
       Boolean AR = newSiteLeaseFncTbl[i].Auto_Renewed__c;
       Double Months = newSiteLeaseFncTbl[i].Lease_Term_In_Months__c;
       Double RMonths = newSiteLeaseFncTbl[i].Renew_Term__c;
       Double RTerms = newSiteLeaseFncTbl[i].Renew_Addl_Terms__c;
       String LeaseID = newSiteLeaseFncTbl[i].id;
       Date MonthBegin = newSiteLeaseFncTbl[i].Start_Date__c;
       Double escamt = (newSiteLeaseFncTbl[i].Escalation_Amount__c/100)+1;
       Double escmth = newSiteLeaseFncTbl[i].Escalation_Month__c;
       Double RentToPay = newSiteLeaseFncTbl[i].Initial_Rent__c;
       Double SLD = newSiteLeaseFncTbl[i].Straight_Line_Depr__c;
       
    if (GT == True)
    {
     Double j = Months;
     
     If (AR == True)
     {
         j = Months + (RMonths * RTerms);
     }
        Integer Count = 1;
        Integer CycleInsert = 1;
      
        for (Integer k = 0; k < j; k++) {
          
         if (escmth == k+1)
         {
          RentToPay = RentToPay * escamt;
         }
         if (k+1 > escmth)
         {
          Count = Count + 1;
         }
         if (Count == 12)
         {
          Count = 1;
          RentToPay = RentToPay * escamt;
         }
       
         SiteFnc__c SiteFnc = new SiteFnc__c(
         Site_Lease__c = LeaseID,
      Date__c = MonthBegin.addmonths(k),
      Cumulative_Def_Rent_Obl__c = SLD * (k+1),
      Rent__c = RentToPay);
     
         followuprecords.add(SiteFnc);
        }
        insert followuprecords;
    }
     }
 }  
}

 
 
I am having a heck of a time trying to figure this one out.  I am deploying a field update (before insert, before update) from eclipse/apex.  It does some basic calcs to get a total dollar value, assigns that value to the field.....and that's pretty much it.
 
It tests and deploys and works in the dev environment just fine.  I cannot deploy it to production however.  I get a total 0% tested lines failure on the class, while it is 94% in the test system. 
 
Also, the assertion fails in the test method.  I set the field to have a default value in the UI (both dev and prod) and again, while the test and dev system work fine, but the prod environment causes the assertion to fail, returning only the default amount instead of the udpated amount that it should be......
 
I have written another very similar class to update a date field based on the same type of trigger, and that one works fine everywhere.....so I am befuddled as to why this one is choking.
 
Anyone else hear of anything like this?

 

Does anyone have any examples of doing this, or can they point to a good example?  I am trying to use a bulk List insert to load a child object per a specific update/insert to the parent object.  I am presently successful, so long as there are 100 records or less.  If I go over 100 records, it gives me a DML error, though I am using the bulk insert as told to.

 

I can find update examples that are similar, but so far nothing that matches what I am trying to do....which doesn't seem to be anything that would be odd.  Mainly I just want to confirm that what I am trying to do is even possible, so if not, I can look into something else.

 

Can I load/update more than 100 records on a child object based on an update/insert of a parent Object?

 

Thank You For ANY help on this.

 

 

I am getting the below error on the myMethod line below.  for the life of me I cannot figure out why....obviously the semi-colon is there.

 

Any help from another pair of eyes would be great!

 

Thanks,


Save error: expecting a semi-colon, found '' SiteLeaseCumCostUpdate/src/classes SiteLeaseFncTblClass.cls line 182

 

 

if (j > 100)

{

myMethod(List<String> ListLeaseID, List<Date> ListDate, List<Decimal> ListCumDefRent, List<Decimal> ListRent, List<Integer> ListTerm);

}

else if (j <= 100)

{

insert followuprecords;

}

else

{

}

Dear salesforce.com users,

 

I want to share with you one Appex class that sorts a List<sObject> by any field in ascending or descending order. The List<sObject> is generated by any SOQL statement, so it can be made of custom and/or standard objects. 

 

Using this class is quite simple, and because I have written unit tests that validates 100% of the code you can easily use it in production sytems.

 

The class performs quite well because the sorting is done in memory (using Maps, Sets and Lists). It also detects if the sort has been done for this field so it does not need to resort (even if it is in reverse order).

 

Before going into details of the Appex class, let me show you how the class is used...

 

The VisualForce page:

Nothing fancy here... Just a page building a datatable with three columns and command buttons on the table headers to sort the data.

<apex:page controller="aaSorterContact">
<apex:form >
<apex:pageBlock >
<apex:pageBlockSection columns="1" ID="AjaxTable">
<apex:datatable value="{!List}" var="acc" Border="1" cellspacing="1" cellpadding="5">
<apex:column >
<apex:facet name="header">
<apex:commandButton action="{!SortByName}"

value="Sort By Name" rerender="AjaxTable" />
</apex:facet>
<apex:outputText value="{!acc.Name}" />
</apex:column>
<apex:column >
<apex:facet name="header">
<apex:commandButton action="{!SortByPhone}"

value="Sort By Phone" rerender="AjaxTable" />
</apex:facet>
<apex:outputText value="{!acc.Phone}" />

</apex:column>
<apex:column >
<apex:facet name="header">

<apex:commandButton action="{!SortByAccount}"

value="Sort By Account" rerender="AjaxTable" />
</apex:facet>
<apex:outputText value="{!acc.Account.Name}" />

</apex:column>
</apex:datatable>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>
</apex:page>

The controller:

Couple things going in here, but that is just to make the page look nice... Nothing really to do with the sorting.

public class aaSorterContact {
private String sortedBy = null;
private Boolean sortAscending = null;
private AP_SortHelper sorter = new AP_SortHelper();
private List<Contact> sortedList = null;

public aaSorterContact() {
sorter.originalList = [SELECT Name, Phone, Account.Name FROM Contact];
}
public PageReference SortByName() {
setSortedBy('NAME');
sortedList = (List<Contact>) sorter.getSortedList('Name', sortAscending);
return null;
}
public PageReference SortByAccount() {
setSortedBy('ACCOUNT');
sortedList = (List<Contact>) sorter.getSortedList('Account.Name', sortAscending);
return null;
}
public PageReference SortByPhone() {
setSortedBy('PHONE');
sortedList = (List<Contact>) sorter.getSortedList('Phone', sortAscending);
return null;
}
public List<Contact> getList() {
if (sortedList == null) {
SortByName();
}
return sortedList;
}
private void setSortedBy(String value) {
if (sortedBy == value) {
sortAscending = !sortAscending;
} else {
sortAscending = true;
}
sortedBy = value;
}
}

 

Let me talk about the easy part first...

 

There are methods that answer the calls from the commandbuttons on the page:

 

  • SortByName
  • SortByAccount
  • SortByPhone

 

These methods follow the same structure:

setSortedBy('NAME');
sortedList = (List<Contact>) sorter.getSortedList('Name', sortAscending);
return null;

First, it calls a method setSortedBy() to find out the ascending or descending order. If the user clicks on a different button, the table is sorted ascending by that column, ortherwise the order is inverted from Ascending to descending and viceversa.

 

Second, it calls the method in the Appex class that does the sorting. (I will explain on detail how to use the Appex class, keep reading) :smileywink:

 

Finally, the controller's method returns a null value to the page.

 

The controller's constructor gets the list from the database.

public aaSorterContact() {
sorter.originalList = [SELECT Name, Phone, Account.Name FROM Contact];
}

Since the buttons use the rerendered propery (using AJAX), the class constructor is only called at the initial page load rather than every time the buttons are clicked, therefore the SOQL gets called only once regardless of how many times the data table gets sorted.

 

Finally, the more interesting part...

 

The Appex class that sorts:

You don't really need to understand how this class works to use it, but those of you who are interested...

public class AP_SortHelper {     // <ID, Position>
private Map<String, Integer> listPosition = null; // <FieldName, <FieldValues>>
private Map<String, List<String>> sortedFieldValuesPerFieldName = null; // <FieldName, <FieldValue, <IDs>>>
private Map<String, Map<String, List<String>>> sObjectIDsPerFieldNames = null;

// Properties
public List<sObject> originalList {get; set;}

// Constructor
public AP_SortHelper() {
originalList = null;
}// Public Method
public List<sObject> getSortedList(String fieldName, Boolean ascending) {
if (originalList == null) {
// Assume that originalList has a not NULL value.
// If the class who uses this method has not assigned a value it will get an Exception which
// needs to be handled by the calling class. // Force the exception...
originalList.clear();
} // Make field name uppercase
fieldName = fieldName.toUpperCase(); // Get sorted list
return makeSortedList(fieldName, ascending);
}
public List<sObject> getSortedList(List<sObject> originalList, String fieldName, Boolean ascending) {
this.originalList = originalList;
sortedFieldValuesPerFieldName = null;
return getSortedList(fieldName, ascending);
}

// Private Methods
private void InitializeFieldName(String fieldName) {
String sObjectID;
Integer position;
String fieldValue;
List<String> sObjectIDs = null;
Set<String> valuesForFieldSet = null; // Sets automatically omit duplicate values
List<String> valuesForFieldList = null;
Map<String, List<String>> sObjectIDsPerFieldValues = null;

// Make sortedFieldValuesPerFieldName
if (sortedFieldValuesPerFieldName == null) {
listPosition = new Map<String, Integer>();
sortedFieldValuesPerFieldName = new Map<String, List<String>>();
sObjectIDsPerFieldNames = new Map<String, Map<String, List<String>>>();
}

// Get (or create) map of sObjectIDsPerFieldValues
sObjectIDsPerFieldValues = sObjectIDsPerFieldNames.get(fieldName);
if (sObjectIDsPerFieldValues == null) {
sObjectIDsPerFieldValues = new Map<String, List<String>>();
sObjectIDsPerFieldNames.put(fieldName, sObjectIDsPerFieldValues);
}
if (!sortedFieldValuesPerFieldName.keySet().contains(fieldName)) {
// Objects need to be initialized
position = 0;
valuesForFieldSet = new Set<String>();
listPosition = new Map<String, Integer>();

for (sObject sObj : originalList) {
sObjectID = sObj.ID;
fieldValue = getValue(sObj, fieldName);

// Add position to list
listPosition.put(sObjectID, position++);

// Add the value to the set (sets rather than lists to prevent duplicates)
valuesForFieldSet.add(fieldValue);

// Get (or create) map of sObjectIDs
sObjectIDs = sObjectIDsPerFieldValues.get(fieldValue);
if (sObjectIDs == null) {
sObjectIDs = new List<String>();
sObjectIDsPerFieldValues.put(fieldValue, sObjectIDs);
}

// Add ID to sObjectIDs
sObjectIDs.add(sObjectID);
}

// Sort set items (Need to convert to list)
valuesForFieldList = new List<String>();
valuesForFieldList.addAll(valuesForFieldSet);
valuesForFieldList.sort();

// Now add it to the map.
sortedFieldValuesPerFieldName.put(fieldName, valuesForFieldList);
}
}
private List<sObject> makeSortedList(String fieldName, Boolean ascending) {
Integer position;
List<String> sObjectIDs = null;
List<String> valuesForFieldList = null; // Initialize objects
InitializeFieldName(fieldName); // Get a list of the same type as the "originalList"
List<sObject> outputList = originalList.clone();
outputList.clear(); // Get a list of sorted values
valuesForFieldList = sortedFieldValuesPerFieldName.get(fieldName);

// for each sorted value
for (String fieldValue : valuesForFieldList) {
// Get lisft of IDs
sObjectIDs = sObjectIDsPerFieldNames.get(fieldName).get(fieldValue);

// for each ID
for (String ID : sObjectIDs) {
// Get position in originalList
position = listPosition.get(ID); // Add each sObject to the list.
if ((ascending) || (outputList.size()==0)) {
outputList.add(originalList[position]);
} else {
outputList.add(0, originalList[position]);
}
}
}
return outputList;
}
private static String getValue(sObject sObj, String fieldName) {
// This returns the sObject desired in case the fieldName refers to a linked object.
Integer pieceCount;
String[] fieldNamePieces;

fieldNamePieces = fieldName.split('\\.');
pieceCount = fieldNamePieces.size();
for (Integer i = 0; i < (pieceCount-1); i++) {
sObj = sObj.getSObject(fieldNamePieces[i]);
}
return String.valueOf(sObj.get(fieldNamePieces[pieceCount-1]));
}

// Unit testing
/*
static testMethod void testSortCustomObject() {
List<TPValue__c> TPValues;
AP_SortHelper sorter = new AP_SortHelper();
String fieldName;

TPValues = [SELECT TPName__r.TPName__c, Value__c FROM TPValue__c LIMIT 50];
fieldName = 'Value__c';
testOrderedList(sorter.getSortedList(TPValues, fieldName, true), fieldName, true);

fieldName = 'TPName__r.TPName__c';
testOrderedList(sorter.getSortedList(TPValues, fieldName, true), fieldName, true);
}
*/
static testMethod void testSimpleField_Ascending() {
testSortingContacts('Name', true);
}
static testMethod void testSimpleField_Descending() {
testSortingContacts('Name', False);
}
static testMethod void testLookupField_Ascending() {
testSortingContacts('Account.Name', True);
}
static testMethod void testLookupField_Decending() {
testSortingContacts('Account.Name', False);
}
static testMethod void testMultipleCalls() {
AP_SortHelper sorter;
sorter = testSortingContacts(null, 'Name', true);
testSortingContacts(sorter, 'Name', False);
testSortingContacts(sorter, 'Account.Name', True);
testSortingContacts(sorter, 'Account.Name', False);
}
static testMethod void testForgotOriginalList() {
Boolean exceptionDetected = false;
AP_SortHelper sorter = new AP_SortHelper();
try {
sorter.getSortedList('Name', true);
} catch (NullPointerException e) {
exceptionDetected = true;
}
System.assert(exceptionDetected);
}
static testMethod void testPassingList() {
AP_SortHelper sorter = new AP_SortHelper();
List<Contact> contacts = [SELECT Name, Phone, Account.Name FROM Contact LIMIT 50];
List<Contact> sortedList = (List<Contact>) sorter.getSortedList(contacts, 'Name', true);
testOrderedList(sortedList, 'Name', true);
}
private static void testSortingContacts(string fieldName, Boolean isAscending) {
testSortingContacts(null, fieldName, isAscending);
}
private static AP_SortHelper testSortingContacts(AP_SortHelper sorter, string fieldName, Boolean isAscending) {
// If sorted is null,create it.
if (sorter == null) {
sorter = new AP_SortHelper();
sorter.originalList = [SELECT Name, Phone, Account.Name FROM Contact LIMIT 50];
}

// Sort list
List<Contact> sortedList = (List<Contact>) sorter.getSortedList(fieldName, isAscending); // Test sort order
testOrderedList(sortedList, fieldName, isAscending);

return sorter;
}
private static void testOrderedList(List<sObject> sortedList, string fieldName, Boolean isAscending) {
String lastValue = null;
String currentValue = null; for (sObject sObj : sortedList) {
currentValue = getValue(sObj, fieldName);
if ((lastValue != null) && (currentValue != null)) { String strDebug = '';
strDebug += '\n--------------------------------------------------------------';
strDebug += '\nSTART';
strDebug += '\n--------------------------------------------------------------';
strDebug += '\n[Ascending:'+isAscending+']';
strDebug += '\n[Previous:'+lastValue+'] [IsNull():'+(lastValue==null)+']';
strDebug += '\n[Current:'+currentValue+'] [IsNull():'+(currentValue==null)+']';
strDebug += '\n[CompareTo:'+(currentValue.compareTo(lastValue))+']';
strDebug += '\n--------------------------------------------------------------';
strDebug += '\nEND';
strDebug += '\n--------------------------------------------------------------';
System.debug(strDebug); if (isAscending) {
System.assertEquals(currentValue.compareTo(lastValue)>=0, true);
} else {
System.assertEquals(currentValue.compareTo(lastValue)<=0, true);
}
}
lastValue = currentValue;
}
}
}

 

How to use this class?

  1. Create an instance of this class AP_SortHelper()
  2. Assign the list to sort. Get this list using SOQL.
  3. Call the getSortedList() method which takes two fields:
    1. The name of the field as it was used in the SOQL
    2. The order (true for ascending, false for descending

 


For now, I have one question to the group...

 

This message is getting long... Is there a better place to post it? The way I see it, AppeXchange is applications not for independent utility classes.

Message Edited by andresperez on 01-28-2009 10:45 AM
The only error I am getting on the below is that it says "File only saved locally, not to server" in the Warnings section, and of course it is not showing up in the ui.
 
I am sure this is something simple, but I have not found it yet.  Any help would be greatly appreciated.
 
Thanks,
 
 
Code:
trigger SiteLeaseEndDate on Site_Lease_Contract__c (after update) {
 private Site_Lease_Contract__c[] newSiteLeaseEndDate = Trigger.new;
 Double Months = newSiteLeaseEndDate[0].Lease_Term_In_Months__c;
 Double y = Months;
 Integer x = y.intvalue();
 newSiteLeaseEndDate[0].End_Date_2__c = newSiteLeaseEndDate[0].Start_Date__c.addMonths(x);
}

 
  • December 10, 2008
  • Like
  • 0
Can Input Text be used in a visualforce email template?  If so how.  It won't let me use apex:form and I can't use an input field with out the apex:form.  Well at least I don't think I can.  Any help would be greatly appreciated.
Hello.  I am writing a trigger which does the following: when Account ownership is changed, query all associated Notes, Open Activities, Contacts (and related Notes and Open Activities), and Open Opportunities (and related Notes and Open Activities) - and change the ownership of all of those records.  I'm concerned that in some rare cases I may be updating more than 100 records as a result of this.

So my question: If i divide this functionality into three triggers - one which does Account Notes and Open Activities, a second trigger which does related Contacts (with Notes and Activities), and a third which does Opportunities (with Notes and Activities) - will this help?   Or will the platform calculate the sum of the records being processed by all three triggers?

Thanks
Chris
  • July 30, 2008
  • Like
  • 0
Is it possible to add an event to a public calendar via apex or the API in general?  I could try it myself, but it's much quicker to ask.

Once I've added an event to a public calendar via the standard UI, I can pull up the record in Apex Explorer etc. and see that it's put in the public calendar ID as the OwnerID, but don't know if apex will let me write that value directly.  (I've noticed that one quirk of the standard UI is that while I can create an event in the public calendar if I start from that calendar, I can't take an existing event and move it to a public calendar by typing the name of the calendar in the Assigned To field (which I assume corresponds to OwnerID.)   I want to make sure there aren't similar limitations on edits for apex.

And is there any way to pull up a list of public calendars and their ID's?  I don't see the object anywhere in the scema explorer.

Thanks much!

  • November 14, 2007
  • Like
  • 0