Salesforceの添付ファイル関連まとめ

すでに世の中いろんな人が書いてくれているけれど、Salesforceの添付ファイルはLEXでUIが変わってユーザが同じ操作をしても格納先のオブジェクトがClassicとLEXで違っている。
このオブジェクトが違うことで、プレビューの挙動も異なっている。たまたまそこに触れたのでメモ。

# Attachmentオブジェクト構成

Classic UIからオブジェクトの関連リストのメモ＆添付ファイルからアップロードすると、**Attachment**オブジェクトに格納されます。正式な情報は[**最新のAttachmentのリファレンス(英語)**](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_attachment.htm)を参照しましょう。
端的には、1ファイルでAttachmentが1レコードでき、紐づけ先のオブジェクトのレコードIDがParentIdに入る、という単純な構成です。特に難しいこともなく、クエリなどに制限もありませんし、Apexから登録したいときにはレコードをinsertすればよいです。

# ContentDocument他オブジェクト構成
LEX UIからオブジェクトの関連リストのメモ＆添付ファイル（あるいはファイル）からアップロードすると、**ContentDocument**オブジェクトはじめ複数のオブジェクトにレコードができます。構造が複雑ですが、[**最新のContentDocumentのリファレンス(英語)**](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_contentdocument.htm)、[**最新のContentVersionのリファレンス(英語)**](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_contentversion.htm)および[**最新のContentDocumentLinkのリファレンス(英語)**](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_contentdocumentlink.htm)の説明に詳細が書かれています。
ContentDocumentがファイルのヘッダー情報を、ContentVersionがバージョン付きのファイル本体を、ContentDocumentLinkがファイルとレコードの紐づきを管理します。さらに内部的にはContentBodyにファイルの本体のBlobが格納されているようです。

### レコードの項目の関連と特別な動作(Apexで扱うときに注意が必要)

* ContentDocumentはinsertできません。
* ファイルを新規保存するときにはContentVersionをinsertします。するとContentVersionレコードに紐づくContentDocumentが作成され、自動的にContentDocumentのLatestPublishedVersionIdに、insertしたContentVersionのIｄがセットされます。
* 同じファイルの新しいバージョンを保存したいときには、ContentVersionレコードを、ContentDocumentIdを既存のContentDocumentIdにしてinsertします。
* ContentVersionをinsertしたときには、内部的にContentBodyが作成され、そのIdがContentVersionのContentBodyIdにセットされます。（通常は意識する必要はありませんが、UI上のプレビューで利用されています）
* ContentDocumentと合わせてinsert実行ユーザに対するShareType=I（推定権限）のContentDocumentLinkが作成されます（たぶん）。
* 特定のレコードに紐づけたいときは、LinkedEntityIdをレコードIdにしたContentDocumentLinkレコードをinsertします。
* どのオブジェクトもトリガーが作成できる

### UI上の操作とレコードの状態

（新規作成時)
1. レコード詳細ページでファイルアップロード操作を行う
1. アップロードしたファイルがContentVersionに保存される
1. ContentVersionと紐づくContentDocumenが作成される
1. 実行ユーザとContentDocumentに紐づくContentDocumentLinkが作成される
1. 表示中のレコードとContentDocumentに紐づくContentDocumentLinkが作成される

(新しいバージョン登録時)
1. ファイル詳細ページから新しいバージョンをアップロードする
1. 新しいContentVersionが、表示していたContentDocumentに紐づけて保存される
1. ContentDocumentのLatestPublishedVersionIdにContentVersionのIdがセットされる

# UI上のプレビューURL

Classic UIでもLEX UIでも以下のようなURLでプレビュー画像が表示できます。数式項目のIMAGE関数に入れれば添付ファイルのサムネイル表示に使えたりします。（ただし、ContentDocumentの場合はURLからは必要なレコードIDが取れないのでApexトリガーなど何らかの手段で取得してカスタム項目などに保持しておく必要があるのがちょっと手間）

<dl>
<dt>Attachimentの場合</dt>
<dd>https://<em><ドメイン></em>/servlet/servlet.FileDownload?file=<em><strong>&lt;AttachmentレコードのID(00P〜)&gt;</strong></em></dd>
<dt>ContentDocumentの場合</dt>
<dd>https://<em><ドメイン></em>/sfc/servlet.shepherd/version/renditionDownload?rendition=<em><strong>&lt;ORIGINAL_Jpg(元サイズ)またはTHUMB120BY90(サムネイル)&gt;</strong></em>&versionId=<em><strong>&lt;ContentVersionレコードのId(068〜)&gt;</strong></em>&operationContext=CHATTER&contentId=<em><strong>&lt;ContentVersionレコードのContentBodyId(05T〜)&gt;</strong></em></dd>
</dl>

renditionについては、[**File Renditionのリファレンス**](
https://developer.salesforce.com/docs/atlas.ja-jp.chatterapi.meta/chatterapi/connect_resources_files_rendition.htm)にある他の値 THUMB240BY180,THUMB720BY480も利用できるみたい。