Work-around for missing “Lookup Relationship” data type custom fields on Task (Activity)

Unlike other standard objects such as Contact and Account, and custom objects, Task (Activity) custom fields cannot be of data type “Lookup Relationship”. (This type allows a relationship to be created with some other object.) So while you can relate a Task to say a Contact through the WhoId field and some other object through the WhatId field, you are stuck if you want to relate the Task to a third object.

Here is a work-around. It uses three custom fields added to Task (Activity):

  • ThirdPartyId – 18 character text field not shown in layout
  • ThirdPartyName – 255 character text field not shown in layout
  • ThirdParty – text formula field shown in layout

The formula produces a basic hyperlink in the Task page:

IF (ThirdPartyId__c != null && ThirdPartyName__c != null, HYPERLINK('/' + ThirdPartyId__c, ThirdPartyName__c, "_self"), null)

(see Hyperlink formula fields for a bit more background) that looks like this:

But there then needs to be a way to choose the related object and all that can be done to allow this is to add a custom button or link to the page. I used a custom button that opens a Visualforce page that in turn allows the related object to be looked up. In my case I wanted to allow either a Contact or an Account to be selected and so needed to use fields of the right lookup type; I re-used an existing managed package custom object to supply those fields but could have created a specific custom object instead. Note that the object instance is never persisted: it just supplies the right meta data for the <apex:inputField>s and the selected id value and name are set back on the Task.

Here is the page:

produced by this Visualforce:

<apex:page standardController="Task" extensions="ChooseThirdPartyController">
    <apex:sectionHeader title="Choose Third Party"/>
    <apex:form >
        <apex:pageBlock mode="edit">
            <apex:pageMessages />
            <apex:pageBlockButtons >
                <apex:commandButton value="Save" action="{!save}" />
                <apex:commandButton value="Cancel" action="{!cancel}" immediate="true" />
            <apex:pageBlockSection title="Task" columns="1">
                <apex:outputField value="{!Task.Subject}"/>
            <apex:pageBlockSection title="Third Party" columns="1">
                <apex:inputField value="{!cr.cve__Contact__c}"/>
                <apex:inputField value="{!cr.cve__Account__c}"/>

with the logic implemented in this controller extension:

public with sharing class ChooseThirdPartyController {

    private ApexPages.StandardController standardController;

    public ChooseThirdPartyController(ApexPages.StandardController standardController) {
        this.standardController = standardController;
        if (!Test.isRunningTest()) {
            this.standardController.addFields(new String[] {String.valueOf(Task.ThirdPartyId__c)});
    private Task t {
        get {
            return (Task) standardController.getRecord();

    // Could use any object here that has the right type of lookup fields on it   
    public cve__ClaimRelationship__c cr {
        get {
            if (cr == null) {
                cr = new cve__ClaimRelationship__c();
                // Default the initial value
                if (t.ThirdPartyId__c != null) {
                    if (t.ThirdPartyId__c.startsWith(Contact.SObjectType.getDescribe().getKeyPrefix())) {
                        cr.cve__Contact__c = t.ThirdPartyId__c;
                    } else if (t.ThirdPartyId__c.startsWith(Account.SObjectType.getDescribe().getKeyPrefix())) {
                        cr.cve__Account__c = t.ThirdPartyId__c;
            return cr;
        private set;
    public PageReference save() {
        if (cr.cve__Contact__c != null && cr.cve__Account__c != null) {
            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 'Pick a Contact or an Account but not both'));
            return null;
        } else {
            if (cr.cve__Contact__c != null) {
                Contact c = [select Id, Name from Contact where Id = :cr.cve__Contact__c];
                t.ThirdPartyId__c = c.Id;
                t.ThirdPartyName__c = c.Name;
            } else if (cr.cve__Account__c != null) {
                Account a = [select Id, Name from Account where Id = :cr.cve__Account__c];
                t.ThirdPartyId__c = a.Id;
                t.ThirdPartyName__c = a.Name;
            } else {
                t.ThirdPartyId__c = null;
                t.ThirdPartyName__c = null;

One thought on “Work-around for missing “Lookup Relationship” data type custom fields on Task (Activity)

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s