• Patrick Conner
  • NEWBIE
  • 60 Points
  • Member since 2014

  • Chatter
    Feed
  • 0
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 24
    Questions
  • 17
    Replies
Below is an outline of a schedulable class I'm trying to deploy. I'm getting the following error on schedule (and in developer console), due to too many IDs in queries: Aggregate query does not support queryMore(), use LIMIT to restrict the results to a single batch.
 
global class TaskRetention implements Schedulable
{
    global void execute(SchedulableContext SC)
    {
AggregateResult[] tasksWithin30Days = [Select whatId from task where createddate = Last_n_days:30 group by whatid];
AggregateResult[] noTask30Days = [Select whatId,max(createddate) maxdate from task group by  whatid having max(createddate) < Last_n_days:30 ];

Id[] hasTaskWithin30Days = new Id[]{};
Id[] noTasksIn30Days = new Id[]{};
String[] whatIdDateTimeList = new String[]{};

for(AggregateResult ar: tasksWithin30Days ){
hasTaskWithin30Days.add((Id)ar.get('whatId'));
}
for(AggregateResult ar: noTask30Days){
noTasksIn30Days.add((Id)ar.get('whatId'));
whatIdDateTimeList.add(''+ar.get('whatId')+ar.get('maxdate'));
}

delete [ Select Id from Task where whatId in :hasTaskWithin30Days and createddate< last_n_days:30];
delete [Select Id from Task where whatId in :noTasksin30Days and whatId_createddate__c not in :whatIdDateTimeList];
}
 
}

I can limit the results to 2k, but this renders the class ineffective. I've read of using QueryMore as a workaround, referencing last returned whatID perhaps? I've also seen references to iterable interfaces and @read, but I don't know how to employ either of those. 

Any help would be greatly appreciated. Thank you.
The following is a class to be used to implement data retention ruleson tasks in our instance. Our own code is quite different than the code below, but using this outline, how would I get started with a test class? This type of class, and some of the functions used, are new to me. Thank you very much for any help.
 
global class TaskRetention implements Schedulable
{
    global void execute(SchedulableContext SC)
    {
AggregateResult[] tasksWithin30Days = [Select whatId from task where createddate = Last_n_days:30 group by whatid];
AggregateResult[] noTask30Days = [Select whatId,max(createddate) maxdate from task group by  whatid having max(createddate) < Last_n_days:30 ];

Id[] hasTaskWithin30Days = new Id[]{};
Id[] noTasksIn30Days = new Id[]{};
String[] whatIdDateTimeList = new String[]{};

for(AggregateResult ar: tasksWithin30Days ){
hasTaskWithin30Days.add((Id)ar.get('whatId'));
}
for(AggregateResult ar: noTask30Days){
noTasksIn30Days.add((Id)ar.get('whatId'));
whatIdDateTimeList.add(''+ar.get('whatId')+ar.get('maxdate'));
}

delete [ Select Id from Task where whatId in :hasTaskWithin30Days and createddate< last_n_days:30];
delete [Select Id from Task where whatId in :noTasksin30Days and whatId_createddate__c not in :whatIdDateTimeList];
}
 
}

 
Hey!

I'd like to purge all objects not matching certain field values.

Is it possible to create a batch class removing all tasks older than a certain date, except the task with an ID matching an Account field "Task ID"? This would leave 1 task with ID = Account.TaskID.

Thanks for any help!
Hey,

I'm trying to figure out how to create a trigger to delete all but the most recent task. Is it possible to order and remove all but most recent?

My actual use-case is this:

For tasks with subject "AAA" on Account "B1", If any task exists with created date < 30 days, purge all tasks with created date >/_ 30 days.
For tasks with subject "AAA" on Account "B1", If no task exists with created date < 30  days, keep most recent task, purge all others.

I'd do the same for tasks with subject not equal to "AAA". Meaning if no task exists with created date <30 days, an account may show the most recent task with subject "AAA" and most recent task with subject "BBB", with older tasks of both subjects purged.

I'm having trouble finding much on this niche use-case, and I'm unsure if it's possible to order tasks by ID or creation date and delete all but the most recent from there.

Thank you very much for your help.

Patrick
Any time staff attempts to relate accounts, or send an email through a contact relating to an Account, the following error results:

Number Too Large
Computed a number that exceeds maximum allowed size. Please contact your administrator; formula fields can cause such errors.

I've found basically nothing on this error online. I've reviewed the obvious possibilities - checked all formula fields, and all numerical fields in general. What's strange is that it may serve this error initially, but if the staff attempts (sometimes it may take 5+ attempts), it will eventually go through. If the staff leaves off the account relation on the outgoing email, it will go through, but this creates tasks floating without account relation.

I suspected perhaps this could be an issue with partner objects, but when reviewing those partner objects successfully created today (mostly account relations) I've been unable to see any issues. Any ideas or thoughts? Thanks!
As the title suggests, I'm trying to have imports (through the bulk API) bypass our dupe rules, while maintaining this rule for users. Is this possible? Thanks!
I have one user account "Imports" for API imports. I import data every 15 minutes under this user account for Account Objects. I also import a larger data set daily under the same user account but for a custom object. Is there a possibility of this simultaneous usage (1 user account, simultaneous imports on two seperate objects) causing issues?

The issue I'm seeing now is that for our daily import, the API returns a successful import, but there is nothing imported and no record of a job created. This only occured after our move from hourly to 15 minute imports on the other object.

Thanks!
We have a custom object "Paid Account", and would like to merge all Paid Accounts into standard Account objects. Both objects share the child object "Contact". I can do this by mapping all fields and upserting Paid Accounts to Accounts, moving Contacts parent Paid Account ID to the relevant Account ID, moving all tasks from Paid Accounts to Accounts, and finally mapping all custom related objects to Account partner objects.

However, it seems there is no way to move the Paid Account history in to Account history, and this is imperitive. Is there any way to do this at all? If not, is there any way to mass merge all these custom objects into the standard objects maintaining custom object history?

Thank you!
I've created a custom button on tasks which will complete the task. However I'd like it to then redirect to the related to: value (usually account page or custom object page).

{!REQUIRESCRIPT("/soap/ajax/29.0/connection.js")}
var TskObj = new sforce.SObject("Task");
TskObj.Id = '{!Task.Id}';
TskObj.Status = 'completed';
var result = sforce.connection.update([TskObj]);
location.reload(true);

Code snippet pasting was causing troubles posting for me so I've pasted in txt above. I've attempted to use window.location.href to load a task.WhatId variable addended to my instances URL unsuccessfully. Any ideas how to pull this off without using triggers? I'm sure it's a simple solution. Thank you.
I've created the following simple custom button on tasks to complete the task:
{!REQUIRESCRIPT("/soap/ajax/29.0/connection.js")}
var TskObj = new sforce.SObject("Task");
TskObj.Id = '{!Task.Id}';
TskObj.Status = 'completed';
var result = sforce.connection.update([TskObj]);
location.reload(true);
Of course the location simply reloads. I've attempted to create a window.location.href command to force load of the WhatId, but I'm not having any luck. Is there a way to do this without setting any triggers? I'm sure the solution is easier than I'm thinking. Thank you!
 
I've created the following simple custom button on tasks to complete the task:
 
{!REQUIRESCRIPT("/soap/ajax/29.0/connection.js")}
var TskObj = new sforce.SObject("Task");
TskObj.Id = '{!Task.Id}';
TskObj.Status = 'completed';
var result = sforce.connection.update([TskObj]);
location.reload(true);

Of course the location simply reloads. I've attempted to create a window.location.href command to force load of the WhatId, but I'm not having any luck. Is there a way to do this without setting any triggers? I'm sure the solution is easier than I'm thinking. Thank you!

 
I'm trying to bulkify the following code, which works well for a single contact and parent account creation:
 
trigger createacc on Contact (after insert) {
list<Contact > con=[select id,lastname,email from contact where id in:Trigger.newMap.keySet()];
list<account >acc =new list<account>();
list<contact>cc1 =new list<contact>();
for(contact c : con)
{
account a =new account ();
a.name=c.lastname;
a.email__c=c.email;
acc.add(a);
}
insert acc;
for(account a1:acc){
system.debug('---------------------this is id --------------------'+a1.id);
for(contact c : con){
c.accountid=a1.id;
cc1.add(c);
}
}
update cc1;
}

Any help would be greatly appreciated! Thank you!
I'd like to mass relate custom objects who match a certain field. 

I have custom object: PPI
I have custom junction object: Related PPI
I have field: Referral

Currently, when staff sees matching referral IDs they manually open both PPI objects and relate one to the other. Sometimes there are up to dozens or more of related PPI objects with matching referral IDs, requiring staff to go into each one and relate to the "Master" object or add all related PPI to each seperate PPI. Is there some way I can automate this process? 

So process would be: IF referral matches on any objects -> Relate all matching objects

Thanks for any suggestions!
There used to be the option to set value type for fields in process builder actions. For example, I do an "Update Record" action, and set a date/time field as type: global constant and value $GlobalConstant.Null. Now I don't see any way to set my date/time field as null (as I can't select global constant value type). Any ideas what happened or how I can set a date/time value as null in PB?

Thanks!!
We currently import data to a field, overwriting old data each time. We'd like to begin importing data to that field and keeping the previous data as well. How can we do this?

My thoughts:
Instead of overwriting field values each import, is there a way to append to the current value? Ex. FIELD1: oldvalue1, newervalue1, importedtodayvalue1

Maybe it's necessary to import to a picklist and create a workflow rule to prepend new data to a field in a list similar to above? How would we go about doing this? We'd like all data to be searchable.

Thanks so much for any help!
Hey! I'm not a developer by training but I've attempted to create a trigger and test class to deploy a solution that grabs the last date of a task with the subject "Email:" and places in a custom field "Last Email Date". I'm having issues getting test class coverage. Any insight or points in the the right direction would be hugely helpful! Thanks!

Trigger:
trigger updateContact on Task(After Insert, after Update)
{

    List<Id> conIds = new List<Id>();
    List<Id> OwnerIds = new List<Id>();
    List<Contact> newConlist =  new List<Contact>();
    String str='Email:';
    
    for(Task tsk:Trigger.new)
    {
        if((tsk.subject).contains(str))
        {
            conIds.add(tsk.whoId);
            OwnerIds.add(tsk.OwnerId);
        }
    }

    List<Contact> conList = [select Last_Email_Date__c from Contact where id in:conIds];

    Map<Id, Contact> conMap = new Map<Id, Contact>([SELECT Id, Last_Email_Date__c FROM Contact WHERE Id IN :conIds]);
    
    
    for(Task tsk : Trigger.new)
    {
        if((tsk.Subject.Contains(str)))
        {
            Contact con = conMap.get(tsk.WhoId);
            
            con.Last_Email_Date__c = tsk.LastModifiedDate;

            newConlist.add(con);
        }
    }

    update newConlist;
}

Test Class:
@isTest
private class TestupdateContact {
  static testMethod void testupdateContact() {
   
    Contact c = new Contact(LastName='Test');
    insert c;
    
    Task tsk = new Task(
             Subject='Email:'
          
    );
    insert tsk;

    c.Last_Email_Date__c=DateTime.parse('05/22/2012 11:46 AM');
    update c;
   
    String checkString = '05/22/2012 11:46 AM';
    system.assertEquals(checkString, [SELECT Last_Email_Date__c FROM Contact WHERE Id = :c.Id].Description);
      }
}


 
I'm trying to create a custom search page. The page and controller work well, but I would appreciate any help with the test class (currently only have 52% coverage). 


CONTROLLER:

public with sharing class WildcardSearchController{
  
// the soql without the order and limit
  private String soql_C {get;set;}  
// the collection of contributions to display
  public List<contact> contributions {get;set;} 
// This is the base soql for building the query
  public String soqlBase_C {
    get{ return soqlBase_C ; }
    set;
   } 
 // Create a query variable for debugging
  public String theQuery{
   get {return theQuery; }
   set;
   }
// Create a variable for record returned count
  Public Integer numberContributions{
   get ;
   set;
   }
// Create a STRING variable for record returned count
  Public string numberContributionsStr{
    get{ return numberContributionsStr; }
   set;
   }
// a set of variables to persist the search parameters   
   Public string Name{ 
       get {return Name; }
       set ;
       }
   Public string Email{ 
       get {return Email; }
       set; 
       }
   Public string Phone{ 
       get {return Phone; }
       set; 
       }
   Public string soqlLimitPage{ 
       get {return soqlLimitPage; }
       set; 
       }
                                                     // END OF VARIABLE Declarations
   
  // init the controller and display some sample data when the page loads CONTRUCTOR
  public WildcardSearchController() {
    soqlBase_C = 'Select Name, Email, Phone from Contact where Phone !=null ';
    system.debug(soqlBase_C);
    soql_C = soqlBase_C;
    runQuery();
  }                                                  // end CONTRUCTOR
  // runs the actual query
  public void runQuery() {     
    try {                                            // Get Contribution Records
      if(soqlLimitPage == null) {
        soqlLimitPage = 'limit 30';
        system.debug('TRY set null soqlLimitPage = ' + soqlLimitPage );
        }
      theQuery = soql_C + ' ' + soqlLimitPage;
      system.debug(' theQuery = ' + theQuery);  
      contributions = Database.query(theQuery);
      system.debug('Contributions list returned = ' + contributions);  
      numberContributions = contributions.size();
      numberContributionsStr = String.valueOf(numberContributions );  
    }               // end try
    catch (Exception e) {
      ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, string.valueof(e))); 
      ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 'Ooops!'));
      ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, soqlLimitPage));
      ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, theQuery));
    }              // end catch
  }                // end runQuery
 
  // runs the search with parameters passed via variables
  public PageReference runSearch() {
                                         // Display search variables
    system.debug('Name = ' + Name );
    system.debug('Email = ' + Email );
    system.debug('Phone = ' + Phone);
    system.debug('soqlLimitPage= ' + soqlLimitPage);
                                        // Build the rest of the soql_ by tacking on and operator parameter  
    soql_C = soqlBase_C;                                          
    if (!Name.equals(''))
      soql_C += ' and Name  LIKE \'%'+String.escapeSingleQuotes(Name )+'%\'';
    if (!Email.equals(''))
      soql_C += ' and Email LIKE \'%'+String.escapeSingleQuotes(Email )+'%\'';
    if (!Phone.equals(''))
      soql_C += ' and Unformatted__c LIKE \'%'+String.escapeSingleQuotes(Phone )+'%\'';
                                         // now, go run the query again and exit
    runQuery();
    return null;
  }                // end runSearch
  
  
  // tests the variables, only function is testing
  Public void runPicklists() {
      List<String> junkList;
      String junkString;      
      junkString = soqlLimitPage;
  }              // end runPicklists   
}                // end class


TEST CLASS

@isTest
private class Test_WildcardSearchController
{

    static testMethod void testController()
    {
        WildcardSearchController CSBC=new WildcardSearchController();
        csbc.Name='bob';
        csbc.Email='gmail';
        csbc.Phone='0299';
        csbc.runQuery();
        
       
       csbc.soqlBase_C= 'select Name, Email, Phone FROM Contact Where Name !=null';
        System.assertEquals(csbc.soqlBase_C, 'select Name, Email, Phone FROM Contact Where Name !=null');
        
        csbc.runQuery();
        

    }
    
    //instantiate the page
    static testMethod void WildcardSearch(){
        PageReference pg = Page.WildcardSearch;
        
        Test.setCurrentPage(pg);
        pg.getParameters().put('Contact.Name', 'bob');
        pg.getParameters().put('Email', 'gmail');
        pg.getParameters().put('Phone', '0299');

        
        //instantiate the controller
        WildcardSearchController controller=new WildcardSearchController();
     
        
        controller.runQuery();

    }
    
}

Thanks!!
I've created a Custom Object "Related List A", with two custom lookup fields: "Current" and "Related", with Related List Labels "Current" and "Related" respectively. The Related List is to be added to a custom account object "PPI".

If I'm in PPI Account A and add another PPI Account (B) to the Related field it will populate under the Current list label for Account A and under the Related List label for Account B. So to make these Accounts have a two-way relationship, I'd have to add both related lists "Current" and "Related" to the Related List A layout, which looks crappy. 

I'm wondering if there is a way to create a two-way relationship with one addition into a related field list? If I associate PPI Account B with PPI Account A in the Related field, why can't they both appear in each other's Related Lists?

This may be convoluted, it's difficult for me to lay it out without showing, haha. I hope someone can help. Thanks!!
I'm trying to create an SOQL Query for the controller of a custom VisualForce page. Is there any way to run a single SOQL query that can search fields in two different non-related objects? I'm aware that this can be done in SOSL, but there are specific reasons SOQL is required for this particular function (please no SOSL responses). 

Basically I'd like to combine the following (examples):

SELECT Name, Email, Phone FROM Contact WHERE Phone != null AND PhoneSearch1__c LIKE '%0149%' order by Name asc limit 75

SELECT Name, Email__c, Phone FROM Account WHERE Phone != null and PhoneSearch1__c LIKE '%0149%' order by Name asc limit 75

This might could be done by assigning the queries as variables? I'm not sure. Any help would be greatly appreciated! Thanks!
Hey!

I'm having some trouble displaying linked results on a VisualForce page; I don't seem to have the best grasp on the outputlink function. What I'd like is for results to be displayed as below, but for the Name to link to the individual contact. Any idea how I can do this? Please let me know if you need more info, and thanks for the help!

Here's what I have for the pageBlockTable:

<apex:pageBlockTable value="{!contacts}" var="contact">

            <apex:column >
                <apex:facet name="header">
                    <apex:commandLink value="Name" action="{!toggleSort}" rerender="results,debug">
                        <apex:param name="sortField" value="Name" assignTo="{!sortField}"/>
                    </apex:commandLink>
                </apex:facet>
                <apex:outputLink value="/!{Contact.id}">{!Contact.Name}</apex:outputLink>
            </apex:column>

            <apex:column >
                <apex:facet name="header">
                    <apex:commandLink value="Email" action="{!toggleSort}" rerender="results,debug">
                        <apex:param name="sortField" value="Email" assignTo="{!sortField}"/>
                    </apex:commandLink>
                </apex:facet>
                <apex:outputField value="{!contact.Email}"/>
            </apex:column>

            <apex:column >
                <apex:facet name="header">
                    <apex:commandLink value="Phone" action="{!toggleSort}" rerender="results,debug">
                        <apex:param name="Phone" value="Phone.name" assignTo="{!sortField}"/>
                    </apex:commandLink>
                </apex:facet>
                <apex:outputField value="{!contact.Phone}"/>
            </apex:column>

          

        </apex:pageBlockTable>
Below is an outline of a schedulable class I'm trying to deploy. I'm getting the following error on schedule (and in developer console), due to too many IDs in queries: Aggregate query does not support queryMore(), use LIMIT to restrict the results to a single batch.
 
global class TaskRetention implements Schedulable
{
    global void execute(SchedulableContext SC)
    {
AggregateResult[] tasksWithin30Days = [Select whatId from task where createddate = Last_n_days:30 group by whatid];
AggregateResult[] noTask30Days = [Select whatId,max(createddate) maxdate from task group by  whatid having max(createddate) < Last_n_days:30 ];

Id[] hasTaskWithin30Days = new Id[]{};
Id[] noTasksIn30Days = new Id[]{};
String[] whatIdDateTimeList = new String[]{};

for(AggregateResult ar: tasksWithin30Days ){
hasTaskWithin30Days.add((Id)ar.get('whatId'));
}
for(AggregateResult ar: noTask30Days){
noTasksIn30Days.add((Id)ar.get('whatId'));
whatIdDateTimeList.add(''+ar.get('whatId')+ar.get('maxdate'));
}

delete [ Select Id from Task where whatId in :hasTaskWithin30Days and createddate< last_n_days:30];
delete [Select Id from Task where whatId in :noTasksin30Days and whatId_createddate__c not in :whatIdDateTimeList];
}
 
}

I can limit the results to 2k, but this renders the class ineffective. I've read of using QueryMore as a workaround, referencing last returned whatID perhaps? I've also seen references to iterable interfaces and @read, but I don't know how to employ either of those. 

Any help would be greatly appreciated. Thank you.
The following is a class to be used to implement data retention ruleson tasks in our instance. Our own code is quite different than the code below, but using this outline, how would I get started with a test class? This type of class, and some of the functions used, are new to me. Thank you very much for any help.
 
global class TaskRetention implements Schedulable
{
    global void execute(SchedulableContext SC)
    {
AggregateResult[] tasksWithin30Days = [Select whatId from task where createddate = Last_n_days:30 group by whatid];
AggregateResult[] noTask30Days = [Select whatId,max(createddate) maxdate from task group by  whatid having max(createddate) < Last_n_days:30 ];

Id[] hasTaskWithin30Days = new Id[]{};
Id[] noTasksIn30Days = new Id[]{};
String[] whatIdDateTimeList = new String[]{};

for(AggregateResult ar: tasksWithin30Days ){
hasTaskWithin30Days.add((Id)ar.get('whatId'));
}
for(AggregateResult ar: noTask30Days){
noTasksIn30Days.add((Id)ar.get('whatId'));
whatIdDateTimeList.add(''+ar.get('whatId')+ar.get('maxdate'));
}

delete [ Select Id from Task where whatId in :hasTaskWithin30Days and createddate< last_n_days:30];
delete [Select Id from Task where whatId in :noTasksin30Days and whatId_createddate__c not in :whatIdDateTimeList];
}
 
}

 
Hey!

I'd like to purge all objects not matching certain field values.

Is it possible to create a batch class removing all tasks older than a certain date, except the task with an ID matching an Account field "Task ID"? This would leave 1 task with ID = Account.TaskID.

Thanks for any help!
Hey,

I'm trying to figure out how to create a trigger to delete all but the most recent task. Is it possible to order and remove all but most recent?

My actual use-case is this:

For tasks with subject "AAA" on Account "B1", If any task exists with created date < 30 days, purge all tasks with created date >/_ 30 days.
For tasks with subject "AAA" on Account "B1", If no task exists with created date < 30  days, keep most recent task, purge all others.

I'd do the same for tasks with subject not equal to "AAA". Meaning if no task exists with created date <30 days, an account may show the most recent task with subject "AAA" and most recent task with subject "BBB", with older tasks of both subjects purged.

I'm having trouble finding much on this niche use-case, and I'm unsure if it's possible to order tasks by ID or creation date and delete all but the most recent from there.

Thank you very much for your help.

Patrick
There used to be the option to set value type for fields in process builder actions. For example, I do an "Update Record" action, and set a date/time field as type: global constant and value $GlobalConstant.Null. Now I don't see any way to set my date/time field as null (as I can't select global constant value type). Any ideas what happened or how I can set a date/time value as null in PB?

Thanks!!
We currently import data to a field, overwriting old data each time. We'd like to begin importing data to that field and keeping the previous data as well. How can we do this?

My thoughts:
Instead of overwriting field values each import, is there a way to append to the current value? Ex. FIELD1: oldvalue1, newervalue1, importedtodayvalue1

Maybe it's necessary to import to a picklist and create a workflow rule to prepend new data to a field in a list similar to above? How would we go about doing this? We'd like all data to be searchable.

Thanks so much for any help!
Hey! I'm not a developer by training but I've attempted to create a trigger and test class to deploy a solution that grabs the last date of a task with the subject "Email:" and places in a custom field "Last Email Date". I'm having issues getting test class coverage. Any insight or points in the the right direction would be hugely helpful! Thanks!

Trigger:
trigger updateContact on Task(After Insert, after Update)
{

    List<Id> conIds = new List<Id>();
    List<Id> OwnerIds = new List<Id>();
    List<Contact> newConlist =  new List<Contact>();
    String str='Email:';
    
    for(Task tsk:Trigger.new)
    {
        if((tsk.subject).contains(str))
        {
            conIds.add(tsk.whoId);
            OwnerIds.add(tsk.OwnerId);
        }
    }

    List<Contact> conList = [select Last_Email_Date__c from Contact where id in:conIds];

    Map<Id, Contact> conMap = new Map<Id, Contact>([SELECT Id, Last_Email_Date__c FROM Contact WHERE Id IN :conIds]);
    
    
    for(Task tsk : Trigger.new)
    {
        if((tsk.Subject.Contains(str)))
        {
            Contact con = conMap.get(tsk.WhoId);
            
            con.Last_Email_Date__c = tsk.LastModifiedDate;

            newConlist.add(con);
        }
    }

    update newConlist;
}

Test Class:
@isTest
private class TestupdateContact {
  static testMethod void testupdateContact() {
   
    Contact c = new Contact(LastName='Test');
    insert c;
    
    Task tsk = new Task(
             Subject='Email:'
          
    );
    insert tsk;

    c.Last_Email_Date__c=DateTime.parse('05/22/2012 11:46 AM');
    update c;
   
    String checkString = '05/22/2012 11:46 AM';
    system.assertEquals(checkString, [SELECT Last_Email_Date__c FROM Contact WHERE Id = :c.Id].Description);
      }
}


 
I'm trying to create a custom search page. The page and controller work well, but I would appreciate any help with the test class (currently only have 52% coverage). 


CONTROLLER:

public with sharing class WildcardSearchController{
  
// the soql without the order and limit
  private String soql_C {get;set;}  
// the collection of contributions to display
  public List<contact> contributions {get;set;} 
// This is the base soql for building the query
  public String soqlBase_C {
    get{ return soqlBase_C ; }
    set;
   } 
 // Create a query variable for debugging
  public String theQuery{
   get {return theQuery; }
   set;
   }
// Create a variable for record returned count
  Public Integer numberContributions{
   get ;
   set;
   }
// Create a STRING variable for record returned count
  Public string numberContributionsStr{
    get{ return numberContributionsStr; }
   set;
   }
// a set of variables to persist the search parameters   
   Public string Name{ 
       get {return Name; }
       set ;
       }
   Public string Email{ 
       get {return Email; }
       set; 
       }
   Public string Phone{ 
       get {return Phone; }
       set; 
       }
   Public string soqlLimitPage{ 
       get {return soqlLimitPage; }
       set; 
       }
                                                     // END OF VARIABLE Declarations
   
  // init the controller and display some sample data when the page loads CONTRUCTOR
  public WildcardSearchController() {
    soqlBase_C = 'Select Name, Email, Phone from Contact where Phone !=null ';
    system.debug(soqlBase_C);
    soql_C = soqlBase_C;
    runQuery();
  }                                                  // end CONTRUCTOR
  // runs the actual query
  public void runQuery() {     
    try {                                            // Get Contribution Records
      if(soqlLimitPage == null) {
        soqlLimitPage = 'limit 30';
        system.debug('TRY set null soqlLimitPage = ' + soqlLimitPage );
        }
      theQuery = soql_C + ' ' + soqlLimitPage;
      system.debug(' theQuery = ' + theQuery);  
      contributions = Database.query(theQuery);
      system.debug('Contributions list returned = ' + contributions);  
      numberContributions = contributions.size();
      numberContributionsStr = String.valueOf(numberContributions );  
    }               // end try
    catch (Exception e) {
      ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, string.valueof(e))); 
      ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 'Ooops!'));
      ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, soqlLimitPage));
      ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, theQuery));
    }              // end catch
  }                // end runQuery
 
  // runs the search with parameters passed via variables
  public PageReference runSearch() {
                                         // Display search variables
    system.debug('Name = ' + Name );
    system.debug('Email = ' + Email );
    system.debug('Phone = ' + Phone);
    system.debug('soqlLimitPage= ' + soqlLimitPage);
                                        // Build the rest of the soql_ by tacking on and operator parameter  
    soql_C = soqlBase_C;                                          
    if (!Name.equals(''))
      soql_C += ' and Name  LIKE \'%'+String.escapeSingleQuotes(Name )+'%\'';
    if (!Email.equals(''))
      soql_C += ' and Email LIKE \'%'+String.escapeSingleQuotes(Email )+'%\'';
    if (!Phone.equals(''))
      soql_C += ' and Unformatted__c LIKE \'%'+String.escapeSingleQuotes(Phone )+'%\'';
                                         // now, go run the query again and exit
    runQuery();
    return null;
  }                // end runSearch
  
  
  // tests the variables, only function is testing
  Public void runPicklists() {
      List<String> junkList;
      String junkString;      
      junkString = soqlLimitPage;
  }              // end runPicklists   
}                // end class


TEST CLASS

@isTest
private class Test_WildcardSearchController
{

    static testMethod void testController()
    {
        WildcardSearchController CSBC=new WildcardSearchController();
        csbc.Name='bob';
        csbc.Email='gmail';
        csbc.Phone='0299';
        csbc.runQuery();
        
       
       csbc.soqlBase_C= 'select Name, Email, Phone FROM Contact Where Name !=null';
        System.assertEquals(csbc.soqlBase_C, 'select Name, Email, Phone FROM Contact Where Name !=null');
        
        csbc.runQuery();
        

    }
    
    //instantiate the page
    static testMethod void WildcardSearch(){
        PageReference pg = Page.WildcardSearch;
        
        Test.setCurrentPage(pg);
        pg.getParameters().put('Contact.Name', 'bob');
        pg.getParameters().put('Email', 'gmail');
        pg.getParameters().put('Phone', '0299');

        
        //instantiate the controller
        WildcardSearchController controller=new WildcardSearchController();
     
        
        controller.runQuery();

    }
    
}

Thanks!!
I've created a Custom Object "Related List A", with two custom lookup fields: "Current" and "Related", with Related List Labels "Current" and "Related" respectively. The Related List is to be added to a custom account object "PPI".

If I'm in PPI Account A and add another PPI Account (B) to the Related field it will populate under the Current list label for Account A and under the Related List label for Account B. So to make these Accounts have a two-way relationship, I'd have to add both related lists "Current" and "Related" to the Related List A layout, which looks crappy. 

I'm wondering if there is a way to create a two-way relationship with one addition into a related field list? If I associate PPI Account B with PPI Account A in the Related field, why can't they both appear in each other's Related Lists?

This may be convoluted, it's difficult for me to lay it out without showing, haha. I hope someone can help. Thanks!!
Hey!

I'm having some trouble displaying linked results on a VisualForce page; I don't seem to have the best grasp on the outputlink function. What I'd like is for results to be displayed as below, but for the Name to link to the individual contact. Any idea how I can do this? Please let me know if you need more info, and thanks for the help!

Here's what I have for the pageBlockTable:

<apex:pageBlockTable value="{!contacts}" var="contact">

            <apex:column >
                <apex:facet name="header">
                    <apex:commandLink value="Name" action="{!toggleSort}" rerender="results,debug">
                        <apex:param name="sortField" value="Name" assignTo="{!sortField}"/>
                    </apex:commandLink>
                </apex:facet>
                <apex:outputLink value="/!{Contact.id}">{!Contact.Name}</apex:outputLink>
            </apex:column>

            <apex:column >
                <apex:facet name="header">
                    <apex:commandLink value="Email" action="{!toggleSort}" rerender="results,debug">
                        <apex:param name="sortField" value="Email" assignTo="{!sortField}"/>
                    </apex:commandLink>
                </apex:facet>
                <apex:outputField value="{!contact.Email}"/>
            </apex:column>

            <apex:column >
                <apex:facet name="header">
                    <apex:commandLink value="Phone" action="{!toggleSort}" rerender="results,debug">
                        <apex:param name="Phone" value="Phone.name" assignTo="{!sortField}"/>
                    </apex:commandLink>
                </apex:facet>
                <apex:outputField value="{!contact.Phone}"/>
            </apex:column>

          

        </apex:pageBlockTable>