Ä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!