Salesforceのカスタマイズを行う上で、基本中の基本となるのが、カスタムオブジェクトやカスタム項目の作成です。 ここのデータモデルがイケてるかイケてないかで、以降のカスタマイズやユーザビリティというのが大きく変わってきます。
必要な情報が、複数のオブジェクトに分散してしまって、それらのレポートをわざわざ一旦エクスポートしては、Excel上でマージして必要なデータを作成しているといったお話もよく聞きます。
今回は、私がこのデータモデルを決める際に、どういったことを考慮して行なっていくかを取り上げたいと思います。
参照関係と主従関係
Salesforceのオブジェクト間のリレーションには、参照関係と主従関係の2種類がありますが、2つのオブジェクト間でリレーションを貼る時、どちらを選択するかというのはSalesforceのデータモデル上、重要な選択になります。 皆さんももうご存知と思いますが、おさらいとしてもう一度両者の特徴を挙げてみましょう。
参照関係
・親レコードの有無は自由
・親オブジェクトとは別々の共有設定が可能
・参照先の親レコードの削除で項目は空欄とするか、親レコードの削除を無効とすることが可能。
・積上集計は不可
・作成後も自由に参照先レコードの変更が可能
主従関係
・主レコードの入力が必須
・所有者および共有設定は親オブジェクトに連動
・主レコードが削除されると従レコードも削除
・従から主への積上集計が利用可能
・作成後の主レコードの変更可否を設定可能
それぞれが異なる特徴を持っているため、実際に保存したいデータの特性によって、どちらのリレーションを利用するかを決めねばなりません。 では、今度は具体的にはどういった要件によって左右されるのかを例に挙げてみます。
・項目の入力を任意としたい→参照関係
主従関係では従レコードは必ず主レコードを持たねばならないため、主レコードのルックアップ項目は常に必須となります。任意入力項目としたい場合には参照関係を適用します。
・親レコードとは別の公開設定が必要(親は公開、子は非公開など)→参照関係
主従関係では、主レコードと同じ所有者、同じ公開設定が従レコードにも引き継がれます。このため、別々に公開範囲を設定したい場合には、参照関係が必須となります。
・見積ヘッダと見積明細など、積上集計を使用してリアルタイムに合計金額等の集計をしたい→主従関係
積上集計が使用できるのは主従関係のみです。参照関係が必須のオブジェクト間で積上を行いたい場合には、非同期Apexを用いた積上用のApexトリガーを追加開発する場合もあります。
このように、様々な条件によって、どちらが適しているかも変わってきますし、複数の条件が衝突する場合もあります。 条件の優先度や、トリガー等の個別開発による代用等も含め、最終的に参照と主従のどちらを適用するかを判断しています。
連結オブジェクト
通常、参照関係や主従関係などSalesforceのリレーションは1:nの関係となります。 1件の親レコードに対して複数件の子レコードがぶら下がる関係です。
たとえば、商談相手として、複数の取引先責任者を入力したい場合、商談に担当者①、担当者②、担当者③といったように、複数個の取引先責任者への参照項目を作成する方法もありますが、この形式だと担当者の数が多くなると項目が足りなくなる可能性もありますし、後々、レポート等で取引先責任者別の商談件数などを求めようとした場合に、グルーピングが出来ないということが起こります。
こういったn:nの関係の場合には連結オブジェクトを作成することで解決が可能です。
なお、上記の例の場合の商談や取引先責任者オブジェクトの関連リストには取引先責任者や商談のリストではなく、連結オブジェクトのリストが、表示されることになりますが、関連リストの表示項目設定では、連結オブジェクトが持つ項目だけでなく、連結先のオブジェクトの項目も並べることができます。
連結オブジェクトでの入力の場合、商談内に担当者項目がある場合と異なって、商談を一旦保存してから、商談担当者レコードを追加で入力する形となりますので、画面遷移数が増えて、ユーザビリティとしては多少下がってしまう面もあります。
我慢して使って貰うのもひとつの手段ですが、VisualforceやSkyVisualEditorで商談入力画面内で一括入力できるような画面を開発して解決するという方法もあります。
別オブジェクトかレコードタイプか
ある2種類のデータを入力するオブジェクトを作成する場合、基本的には2つの別個のオブジェクトを作成すると思います。 しかし、ケースによっては、同一オブジェクトの別レコードタイプとして作成した方が適した場合があります。
例えば、予算データと実績データ、予定と結果、収入と支出などのデータの場合、集計時に両者の対比を行いたいというニーズが出てきます。 別オブジェクトとして作成してしまうと、レポートやダッシュボードなどで思うようにグラフ化できず苦労することが多々あります。
こういう場合は同じオブジェクトの異なるレコードタイプとして、ページレイアウト等も分けておき、集計で使いたい金額等の項目は、どちらのページレイアウトでも共通で使うようにしておくことで、レポート上のグルーピングにレコードタイプを指定するだけで、すぐに対比を行うことが可能になります。(収支の金額をどちらも絶対値で入れている場合には、支出の+-を符号変換する数式項目を作っておけば収支がプラスいくら、マイナスいくらといった見方もできます。)
とりあえず入力できるオブジェクトを作ってしまって、後から集計しようと思ったらうまく行かずに苦労したという話はよく聞きますが、データモデルを決める時点で、出力を想定したモデルを心がけておくことで、後の祭りを防ぐことができます。
レコードタイプと関連リスト
レコードタイプを使用した場合に、対象オブジェクトの参照先のオブジェクト側の関連リストでは、2種類のデータが入り混じって表示されてしまうことで、ユーザビリティの低下に繋がる場合があります。
例えば、取引先の下に、店舗と倉庫という2種類のデータを持たせたいとします。商品の送り先として、店舗と倉庫のどちらも送付伝票に指定したいので、2種をどちらも送り先マスタとして指定したいとしたら、「店舗・倉庫」という1オブジェクト内で、「店舗」レコードタイプと「倉庫」レコードタイプを使い分けることで、送付状オブジェクトから一元的に送り先の指定が可能となりますが、このままでは取引先の下には「店舗・倉庫」関連リストに両者が混在して表示されてしまうため、店舗リストと倉庫リストを別々に出して欲しいというリクエストがありました。
こうした場合には、「店舗・倉庫」オブジェクトに「取引先」の参照項目を2つ作成して、「店舗」関連リストと「倉庫」関連リストに分けて、取引先画面上に表示することが可能になります。
具体的には参照項目を「取引先_店舗」と「取引先_倉庫」の2つ作成し、店舗レコードタイプのページレイアウトには「取引先_店舗」、倉庫レコードタイプのページレイアウトには「取引先_倉庫」を設置します。 こうすることで、取引先画面には「取引先_店舗」と紐付いた「店舗」関連リストと、「取引先_倉庫」に紐付いた「倉庫」関連リストと、関連リストを分けて表示してやることが可能になります。
マスタオブジェクトと選択リスト
ユーザに対して選択式での入力をさせたい場合、それを参照(または主従)関係を持ったマスタオブジェクトからルックアップ画面で選択させるか、それとも選択リスト項目を作成して、ドロップダウン形式で選択させるかについても管理者は選択が必要です。 どちらを選ぶべきかは要件によって異なります。表にしてみましょう。
・静的な値を単一画面上から簡単に選択したい→選択リスト
単に入力値を制限してユーザに入力させたい場合、選択リストはドロップダウン表示で1画面内で入力が完結しますので、ユーザビリティの観点から選択リストの方が入力負荷は低くなります。
・ 選択肢の件数が膨大。条件検索が必要。→マスタオブジェクト
ドロップダウンで表示するには件数が膨大だったり、そこから選択するためには検索を必要とする場合には選択リストは適しません。かえってユーザビリティを下げることになりますので、別画面から検索が可能なマスタオブジェクトを適用します。
・ユーザ側でマスタメンテが必要→マスタオブジェクト
選択リストの編集には、プロファイル上「アプリケーションのカスタマイズ」の権限が付与されたユーザである必要があります。 かなり強力な権限のため、一般のユーザに付与するのは運用上のリスクも大きいため、ユーザが頻繁に選択肢の追加・削除・変更を行いたい場合には、マスタオブジェクトを作成して、オブジェクトの編集権限を付与した方が安全です。
・リスト値の他に、コードや価格などの情報も持たせたい→マスタオブジェクト
選択リストは、選択肢の表示名しか持つことができません。選択肢に応じてコード番号や単価など、付随した情報を保持・利用したい場合には、マスタオブジェクトに項目を追加する形となります。
殆どの場合、マスタオブジェクト化しておいた方が、より汎用性が高まりますが、マスタオブジェクトを作成することで発生するデメリットも存在します。
・オブジェクト数の上限があるライセンスの場合、残りオブジェクト数が消化される。
・別ウィンドウでルックアップ画面を開くので、画面遷移数が増えるため、ユーザビリティは低下する。
・ルックアップ画面の初期表示では最近使ったレコードしか表示されないため、検索操作が必要となる。
ルックアップ画面での入力は、選択リストと比べて、エンドユーザから入力が面倒と受け取られる可能性があります。 SkyVisualEditorでは、内部的には参照関係のマスタレコードを画面上はドロップダウン式で選択可能とする部品も用意されています。
参照型か値型か
マスタオブジェクトに関連して、マスタオブジェクトを作成したとして、それを参照する子オブジェクト側で、マスタオブジェクトのデータを利用する際にも、注意点があります。
たとえば見積明細には商品マスタへのルックアップ項目があり、そこで商品を選択すると、商品マスタから取得した単価と、入力された数量や、消費税率を乗じて、明細当たりの小計を取ったりします。 この時に、見積明細側で単価を出す際や、消費税を計算する際に、数式項目を利用するケースが多いと思います。 便利な数式項目ですが、落とし穴があって、後から商品マスタが更新や削除された時のことを想定しておく必要があります。
たとえば3ヶ月前に作成した見積が、今日注文があって開いてみたら、数日前の価格改定で当時と金額が変わってしまうことが起こります。 数式項目は常に、最新のマスタデータに連動してしまいますので、こういった場合には、見積作成時に表示された単価の値を、ワークフロールールと項目自動更新を使って、保存時に見積明細側の通貨項目にコピーしておいてやる必要があります。
消費税計算についても同様で、レコード作成当時とレコードを開いたタイミングとで、税率が異なる場合などに影響を受けないように考慮する必要があります。 マスタに連動させたいのか、マスタが変わっても、レコードが保存された当時の値を残しておく必要があるのか、項目を作成する際には意識するようにしましょう。
レポートタイプ
意外と知られていないのですが、カスタムレポートタイプを作成すると、実際にオブジェクトに作成した項目名とは別に、レポート上で表示する際に使用したいレポート用の項目名を定義することができます。 入力画面で分かりやすい項目名と、レポート上で表示したい項目名を別々に定義できます。
如何だったでしょうか?
Salesforceのリレーションや項目は、データベーステーブルと画面UIが一体として定義していくもののため、リレーショナル・データベースの経験がある方でも戸惑う部分があります。ましてや、そういった経験も無い方がオブジェクトや項目を作成した場合、後から思わぬ壁にぶつかることが起こり得ます。
Salesforceではブラウザ上からマウス操作で簡単にオブジェクトや項目を作成することが出来ますが、作成する前には画面からの入力のしやすさや、レポートでの集計のしやすさ等、考慮しておく点は意外と多々あったりします。
勿論、後から必要となった時点で項目を変更したり追加したりといったことも簡単に出来ますが、忘れてはいけないのはその時点で既に入力されてしまっているデータのメンテナンスも必要となってくることで、DataLoaderでエクスポートしたりインポートしたり検証したり、後からデータモデルを変更することは結構なオーバーヘッドを発生させるので、可能な限り事前に様々な要素を考慮・検討してデータモデルを決定するようにしましょう。