1SOQLで全項目の値を取得(特定の子リレーションの値も同時に取得)
public class SOQLUtil {
// 指定オブジェクトのみを取得対象とする
public static String generateQueryString(String name) {
// sObjectを生成
sObject newObj = (sObject)Type.forName(name).newInstance();
// 設定情報を取得
Schema.DescribeSObjectResult descResult = newObj.getsObjectType().getDescribe();
// 整形して戻す
return 'Select ' + concatSet(descResult.fields.getMap().keySet(), ', ') + ' From ' + name;
}
// 指定オブジェクトと指定された子リレーションも取得対象とする
public static String generateQueryString(String name, Set<String> childSet) {
// sObjectを生成
sObject newObj = (sObject)Type.forName(name).newInstance();
// 設定情報を取得
Schema.DescribeSObjectResult descResult = newObj.getsObjectType().getDescribe();
// 取得用項目Set
Set<String> targetSet = new Set<String>{concatSet(descResult.fields.getMap().keySet(), ', ')};
// 子リレーションを取得
for (Schema.ChildRelationship child : descResult.getChildRelationships()) {
String rName = child.getRelationshipName();
// 取得対象ではない場合、次へ
if (!childSet.contains(rName)) continue;
// 子リレーションの設定情報を取得
Schema.DescribeSObjectResult childDesc = child.getChildSObject().getDescribe();
Set<String> tempSet = getAllFieldsForChild(childDesc);
targetSet.add('(Select ' + concatSet(tempSet, ', ') + ' From ' + rName + ')');
}
// 整形して戻す
return 'Select ' + concatSet(targetSet, ', ') + ' From ' + name;
}
// 子リレーションの項目取得
private static Set<String> getAllFieldsForChild(Schema.DescribeSObjectResult descResult) {
Set<String> retSet = new Set<String>();
Map<String, Schema.SObjectField> fieldMap = descResult.fields.getMap();
for (String api : fieldMap.keySet()) {
// 子リレーションでBase64は取得対象外
if (fieldMap.get(api).getDescribe().getType() == Schema.DisplayType.base64) continue;
retSet.add(api);
}
return retSet;
}
// 連結
private static String concatSet(Set<String> strSet, String sep) {
String retStr;
for (String str : strSet) {
retStr = retStr == null ? str : retStr + sep + str;
}
return retStr == null ? '' : retStr;
}
}
コードサンプル(呼び出し側)
String objectName = 'Account';
Set<String> childSet = new Set<String>{'Contacts', 'Cases'};
String query;
List<sObject> sojList;
// 対象オブジェクトの項目のみ
query = SOQLUtil.generateQueryString(objectName);
sojList = Database.query(query);
// 対象オブジェクトの項目と子リレーション
query = SOQLUtil.generateQueryString(objectName, childSet);
sojList = Database.query(query);
SOQLでは「Select *」を利用することはできませんが、「Describe」を利用して指定したオブジェクトの項目と子リレーションの項目を取得してSOQLで全ての項目の情報を取得することが可能です。
注意点:1SOQLで取得可能な子リレーション数は20個までとなりそれ以上指定するとエラーとなります。
describeSobject
項目セットの取得
コードサンプル
String query = 'Select Id';
for (Schema.FieldSetMember fsm : Account.sObjectType.getDescribe().fieldSets.getMap().get('DetailPage_FieldSet').getFields()) {
query += ', ' + fsm.getFieldPath();
}
query += ' From Account ';
List<sObject> sojList = Database.query(query);
対象オブジェクトの項目セットからVisualforceページの表示に必要な項目を動的に取得してSOQLを発行することができます。また、オブジェクト名や項目セットも動的に指定できるようにするとより汎用性の高い処理が実現できます。
以下のように項目セットは「Describe」を利用しなくても取得可能です。
コードサンプル
なお、Visualforceページでの項目セットの利用方法等については弊社佐竹によるエントリ「セールスフォースの項目セットを利用してメンテナンス性を高めよう」を参照してください。
取得したIDが期待しているオブジェクトのIDか確認
コードサンプル
URLパラメータでIDの受け渡しを行うことも多いと思いますが、そのIDが目的のオブジェクトのIDであるか確認できます。
注意:一部オブジェクトにはPrefixがない場合もあります。
describeField
項目に対しても「getDescribe」メソッドが用意されていて項目の設定情報(API参照名、表示ラベル、文字数など)を取得することができます。
例えば以下の用途があります。
選択リスト値を動的に変更
コードサンプル
例では商談オブジェクトの受注チェックボックスがTRUEの場合のみ受注で始まるフェーズのみ選択リストで表示するようにしています。
注意点:1回のトランザクションで取得可能な選択リスト項目数は100個までです。(リスト値の数ではありません)
番外編
特定の「sObject」に対してのみ「Describe」を行う場合、以下のように簡単に行えます。
コードサンプル
Schema.DescribeSObjectResultdescR=Account.sObjectType.getDescribe();
また、オブジェクト名だけが文字列で取得できていて「Describe」を行いたい場合は以下のように先に「sObject」を解決してから「Describe」を行う必要があります。
コードサンプル
どれを利用しても取得できる結果は同じになりますが、実行時間には若干の差異が出てきます。環境によりますが、私のDeveloperEditionではパターン2が最も早く続いてパターン3、パターン1(パターン2の約6倍)となりました。ただしパターン3は初回実行でパターン2の約5倍、2回目以降はパターン2より若干遅いくらいです。(ミリ秒の差ですのでそこまで大きく差異はないですが)
参照
http://sfdcsrini.blogspot.com/2015/05/schemadescribesobjectresult-in-apex-and.html