本記事では、Salesforceのテキスト文字列(String型)の大文字小文字区別によるSQOLとApex処理の扱いの違いについて説明していきたいと思います。
この問題でエラーが発生した場合に、なかなか原因が特定できず解決まで時間がかかったしまったという人も多いのではないでしょうか。
では、さっそく問題点と解決策について説明していきたいと思います。
Salesforceのテキスト項目の属性について
Salesforceでオブジェクトにテキスト項目を作成する場合、以下のような属性が設定できます。
- 項目表示ラベル:テキスト項目のラベル名
- 文字数:最大で255文字まで設定可能
- 項目名:API参照名(Apexなどのプログラムから当該項目を利用する際に使用する名称)※カスタム項目の場合は、[__c(半角のアンダーバーが2つ)]が付与されます。
- 説明:項目に関する説明を記述します。
- ヘルプテキスト:項目のヘルプに表示される内容を記述します。
- 必須項目:項目の入力を必須とします。※ただし画面上だけの制御となるため、データインポートなどでは空文字、ブランク、NULLで登録することができます。
- ユニーク 値の重複を許可しない:入力された文字列の重複を許可するかしないかを制御する。さらに、大文字小文字を同一と扱うか扱わないかのチェックも実施します。
- 「ABC」と「abc」を値の重複として扱う(大文字と小文字を区別しない)
- 「ABC」と「abc」を別の値として扱う(大文字と小文字を区別する)
- 外部ID:外部システムの一意のレコード識別子として設定する:
- カスタムレポートタイプに自動追加:チェックすると項目追加時にカスタムレポートタイプに自動的に項目が追加されます。
ユニーク(値の重複を許可しない)場合の挙動について
オブジェクトにテキスト項目を作成する際、ユニークにチェックをすると、その項目は同じ値のデータが登録できなくなります。
※Salesforceの標準機能で重複チェック処理が実行されるようになります。また、大文字小文字を区別するかしないかにより重複チェックの内容も異なります。
標準画面上から操作する場合の挙動
標準画面からテキスト項目に値を入力して保存した場合の挙動については以下のようになります。
※レコード1を登録後に、レコード2の値を設定した場合の実行結果を表示しています。
No. | 重複チェックあり | 大文字小文字を区別 | レコード1 | レコード2 | 実行結果 |
1 | なし | - | UID001 | UID001 | 正常 |
2 | あり | 区別する(Casesensitive__c) | UID001 | UID001 | 重複エラー |
3 | uid001 | uid001 | 重複エラー | ||
4 | UID001 | uid001 | 正常 | ||
5 | 区別しない(CaseInsensitive__c) | UID001 | UID001 | 重複エラー | |
6 | uid001 | uid001 | 重複エラー | ||
7 | UID001 | uid001 | 重複エラー |
※上記の通り、大文字小文字を区別する場合には、[UID001]と[uid001]は別文字列として判断されるため、画面上に以下のようなエラーが表示されます。
画面以外にも、データのインポートなどの処理でも同様に重複チェックが実行されるようになるため、Apexトリガーなどの処理で重複チェックをする必要がなくなります。
ユニーク項目に対してSQOLを実行する場合の注意事項
作成したテキスト項目(大文字小文字を区別する)と(大文字小文字を区別しない)の項目を抽出条件としてレコードを取得するSOQLを実行してみます。
実行前のレコードは以下の2件を登録しておきます。
まずは、SOQLでWHERE句を指定せず全件取得してみます。
SELECT Id, CaseInsensitive__c, CaseSensitive__c
FROM CustomObject__c
次は、大文字と小文字を区別しない(CaseInsensitive__c)の項目に対して、大文字('UID001')で検索を実行
SELECT Id, CaseInsensitive__c, CaseSensitive__c
FROM CustomObject__c
WHERE CaseInsensitive__c ='UID001'
大文字のレコードが抽出されました。
次は、大文字と小文字を区別しない(CaseInsensitive__c)の項目に対して、小文字('uid001')で検索を実行
SELECT Id, CaseInsensitive__c, CaseSensitive__c
FROM CustomObject__c
WHERE CaseInsensitive__c ='uid001'
小文字で検索した場合に、大文字のレコードが抽出されます。同様に、IN句を使って、以下のように大文字と小文字両方を指定しても、1レコード(大文字)しか返却されないため注意が必要です!
SELECT Id, CaseInsensitive__c, CaseSensitive__c
FROM CustomObject__c
WHERE CaseInsensitive__c in('uid001','UID001')
次は、大文字と小文字を区別する(CaseSensitive__c)の項目に対して、大文字('UID001')で検索を実行
SELECT Id, CaseInsensitive__c, CaseSensitive__c
FROM CustomObject__c
WHERE CaseSensitive__c ='UID001'
大文字のレコードが抽出されます。
次は、大文字と小文字を区別する(CaseSensitive__c)の項目に対して、小文字('uid001')で検索を実行
SELECT Id, CaseInsensitive__c, CaseSensitive__c
FROM CustomObject__c
WHERE CaseSensitive__c ='uid001'
小文字のレコードが抽出されます。
上記の結果を取り纏めると以下のようになります。
No. | WHERE句 | SOQL実行結果 | 実行結果 |
1 | 条件なし(全件取得) | UID001、uid001(2件) | 全件取得 |
2 | 大文字小文字を区別しない(CaseInSensitive__c)='UID001' | UID001(1件) | 大文字を取得 |
3 | 大文字小文字を区別しない(CaseInSensitive__c)='uid001' | UID001(1件) | 大文字を取得 |
4 | 大文字小文字を区別する(CaseSensitive__c)='UID001' | UID001(1件) | 大文字を取得 |
5 | 大文字小文字を区別する(CaseSensitive__c)='uid001' | uid001(1件) | 小文字を取得 |
上記の結果通り、区別する(CaseSensitive__c)の項目の場合、小文字を指定すると小文字が一致するデータが取得できますが、それ以外のものは大文字のレコードしか抽出されませんでした。
重複チェックのテキスト項目を利用してSOQLを発行する際は、注意が必要です。
ユニーク項目に対してApexで扱う場合の注意事項
ユニーク項目に対して、SOQLを実行した結果については説明した通りですが、今度はApexでユニーク項目を扱い場合の注意事項について説明します。
例えば、外部システムからデータをインポートして、Salesforce内の外部IDと比較する処理でよく発生するバグがあります
Apexプログラムを利用して、外部システムからデータを取り込む際に、外部システムの[項目A]をキーとして、Salesforceの格納先オブジェクトの外部ID項目[項目B]と比較をするロジックを組み込んだとします。
Salesforce側の[項目B]はユニーク設定(大文字小文字を区別しない)として定義されているとします。またIF連携要件としては、キーの比較の際に、大文字・小文字の比較をして異なる場合は別データとして扱うという要件とします。
①まず、Apexで以下のような外部データを読み取ったとします。
[外部システムから取得したレコード]
No. | 項目A(キー) | 郵便番号 | 住所 |
1 | Key001 | 111-1111 | 東京都xxxxx |
2 | KEY001 | 222-2222 | 埼玉県xxxxx |
②読み取ったレコードの項目Aをキー、SFDCに一致するレコードがあるかチェックするためにSOQLで以下のテーブルから一致するデータを検索します。
[SFDCカスタムオブジェクトに登録済みのレコード]
No. | 項目B(外部ID)大文字小文字区別しない | 郵便番号 | 住所 |
1 | Key001 | 111-1111 | 東京都xxxxx |
2 | KEY001 | 222-2222 | 埼玉県xxxxx |
3 | KEY002 | 333-3333 | 神奈川県 |
外部システムの項目Aをキーとして以下のSQOLを発行します。
SELECT ID, 項目B
FROM SFDCオブジェクト
WHERE 項目B IN ('Key001','KEY001');
③結果としては、SFDCカスタムオブジェクトからは、No.2のレコードだけが取得されます。
No. | 項目B(外部ID)大文字小文字区別しない | 郵便番号 | 住所 |
2 | KEY001 | 222-2222 | 埼玉県xxxxx |
※取得したレコードは、MAP<項目BのString,Object> マップ変数(XMAP)へ格納しておきます。
④外部システムレコードをFor分で繰り返し処理して、その中で③で作成したマップを使って、キーが一致するレコードが取得できるかチェックします。
for ( ExRecords rec:①で取得したレコードのリスト ){
Object obj = XMAP.get(obj.項目A);
}
上記のようなコードを書いた場合に、XMAPの中には、(’KYE001’)のみしか格納されていないため、外部システムのレコード('key001')は取得できません。
★項目をユニーク(大文字小文字を区別する)としておくと、SFDCからはNO.1のレコード('key001')とNo.2('KEY001')のレコードが取得されるため、全件存在するという結果となります。
まとめ
Salesforceでは、ユニーク設定によって、処理結果が異なってくることがご理解いただけたと思います。
オブジェクトの項目設計をする際はユニーク設定の違いを意識して行うようにしてください。