Ärgernis #1 Ereignisse, Email-Vorlagen und Polymorphismus

Alles hat damit angefangen, in einer Email die Uhrzeit eines Ereignisses (Event) einzutragen. Seitdem nehmen die Umwege, die wir in unserer Org gehen müssen, um Events und Email-Vorlagen unter einen Hut zu bringen, kein Ende. Erst vor kurzem die nächste böse Überraschung. Aber der Reihe nach:

Ereignisse und Aufgaben sind einzigartig im sObject Universum. Sie sind Spielarten des Activity-Objekts und gehorchen besonderen Regeln.

  • So ist es erst seit kurzem möglich, ein Referenz-Feld (Lookup) auf einem dieser Objekte überhaupt anzulegen.
  • Aufgaben und Ereignisse werden nach einem Jahr archiviert und können nicht mehr reportet werden
  • die maximale Textlänge auf einem Textfeld ist 255 - Aktivitäten unterstützen keinen Richtext.
  • Sharing / Sichtbarkeit funktioniert contra-intuitiv, da man zwar zB Tasks auf private setzen kann, doch das wird ignoriert, sofern das Eltern-Objekt andere Sharing Einstellungen besitzt
  • Keine Workflow Email Alerts
  • Keine Queues
  • Keine Notizen und Anhänge
  • Beim Import von Tasks und Events werden die zugehörigen Eltern-Objekte gelockt
  • Und auch der Betreff einer Aufgabe/ eines Ereignisses ist eine in Salesfoce einzigartige Mischung aus Textfeld und Auswahlliste.

Schuld an allem? Polymorphismus. Dieses sperrige Wort ist anhand eines anderen sObjekts schnell erklärt. Case.AccountId bezieht sich immer und ausschließlich auf einen Account sonst nichts. Event.WhatId kann sich beispielsweise auf eine Opportunity, einen Account oder etwas anderes
wie ein Custom Object beziehen, dasselbe gilt für Event.WhoId, wobei in diesem Fall lediglich Contact oder Lead möglich sind.

Mit

SELECT Id  
FROM Event  
WHERE What.Type IN ('Account', 'Opportunity')  

lassen sich Ereignisse filtern.

Pro Tip: Event.Account wird immer richtig aufgelöst, tatsächlich klappt standardsObject.Account immer.

Besonders umständlich wird das in Visualforce Email Vorlagen. Diese wirken polymorph, da der Verweis auf das zugehörige Objekt mittels relatedTo und Recipient aufgerufen wird - sind aber nur syntaktische Konstruktionen. Strenggenommen können aber nur Felder auf Objekte polymorph sein. Da solche Felder unterschiedliche Objekte wie Accounts, Cases oder CustomObjects betreffen können, hat sich Salesforce etwas einfallen lassen: Das sObject Name, das eine Abstraktion ist und bei weitem nicht alle Felder und Relationen erhält, die man sich wünscht oder zunächst vermutet.

[Name] is used to retrieve information from related records where the related record may be from more than one object type (a polymorphic foreign key). For example, the owner of a case can be either a user or a group (queue). This object allows retrieval of the owner name, whether the owner is a user or a group (queue). You can use a describe call to access the information about parents for an object, or you can use the who, what, or owner fields (depending on the object) in SOQL queries. This object cannot be directly accessed.

Was hat das für Auswirkungen?

<messaging:emailTemplate subject="Hallo, Welt!" recipientType="Contact" relatedToType="Event">  
<messaging:HtmlEmailBody >  
<h1>Hallo, Welt</h1>  
{!relatedTo.Owner} <!-- funktioniert -->
{!relatedTo.Owner.myCustomField__c} <!-- funktioniert nicht -->
</messaging:HtmlEmailBody>  
</messaging:emailTemplate>  

Bei relatedTo.Owner.myCustomField__c erscheint der Fehler: 'Error: Invalid field myCustomField__C for SObject Name' - eben weil nicht, wie zu vermuten, ein User aufgelöst wird, sondern ein Name Objekt. Und das obwohl die Dokumentation zu Event.Owner sagt:

Contains the ID of the user who owns the event. Label is Assigned to ID.

Event.Owner ist entgegen dem Anschein polymorph, nur nicht auf Event, sondern auf Task, bei dem auch ein Kalender Owner sein kann. Da Task und Event im Hintergrund dieselbe Struktur haben, erhält man Name statt User.

Um diesem Problem gerecht zu werden, setzen wir auf Visualforce Components in den Email Vorlagen, die im Zweifel mittels Apex Code alles richtig auflösen können.

PS: Wer sich die Doku zu sOQL und Polymorphismus angesehen hat, findet dort den Verweis auf TypeOf, womit sich einige der Schwierigkeiten einfach in Luft auflösen würden.

SELECT  
    TYPEOF What
        WHEN Account THEN Phone
        ELSE Name
    END
FROM Event  
WHERE CreatedById IN  
    (
    SELECT CreatedById
    FROM Case
    )

ABER: Erstmals 2012 in einem einen Blog-Post zu Winter '13 beworben, ist typeOf nur in Developer Editionen oder auf Anfrage in der Sandbox erhältlich, d.h. nicht generally available. Buh, Salesforce, Buh!

Show Comments