[Salesforce]ApexでレコードタイプID取得

ApexでレコードタイプID取得コードを共有します。

/**
  * getRecordTypeIdByQuery
  * SOQLを使用してレコードタイプIDを取得
  * @param : オブジェクト名(DeveloperName)
  * @param : レコードタイプ名(DeveloperName)
  * @return : レコードタイプID
  */
private ID getRecordTypeIdByQuery( String objectName, String recordTypeName ){

  List<RecordType> recordTypeList = [
    SELECT Id
      FROM RecordType
      WHERE SobjectType = :objectName
      AND DeveloperName = :recordTypeName
  ];

  return ( recordTypeList != null && !recordTypeList.isEmpty() ) ? recordTypeList[0].Id : null ;
}

テストする。

Salesforceの開発コンソルにて、上記のソースコードを登録し、以下のソースコードで呼び出す。

ID recordtypeid = getRecordTypeIdByQuery('Account','Business_Account');
System.debug('recordtypeid:'+recordtypeid);

結果

recordtypeid:0xxxx0000000xxxxxx

[Salesforce]salesforce カスタムボタンのjavascriptでレコードタイプ取得

salesforce カスタムボタンのjavascriptでレコードタイプ取得方法の例を共有します。

{!REQUIRESCRIPT("/soap/ajax/29.0/connection.js")}
var result = sforce.connection.query("Select Id, DeveloperName, Name From RecordType Where SobjectType = 'TestCustomObject__c' AND DeveloperName = 'devtest' limit 1");
var records = result.getArray("records");
alert('id='+records[0].Id+",Name="+records[0].Name+",DeveloperName="+records[0].DeveloperName);

ここで、

TestCustomObject__c : カスタムオブジェクトAPI参照名

レコードタイプ名 : devtest

レコードタイプ表示ラベル : test

[Salesforce]ObjectNameからPrefix取得

SalesforceのObjectNameからPrefixを取得するのを共有します。

開発コンソル画面にて「Debug」タブの「Open Execute Anonymous Window」画面にて以下を実行する。

    String objName ='Account';	
    schema.sObjectType sObjType = Schema.getGlobalDescribe().get(objName);
    system.debug('prefix:'+(sObjType.getDescribe().getKeyPrefix()));

DebugLog結果は以下です。

prefix:001

[Salesforce]You have uncommitted work pending. Please commit or rollback before calling out

Salesforceの「You have uncommitted work pending. Please commit or rollback before calling out」エラーの原因と解決策について共有します。

・原因

開発においては、外部 Web Service から取得した結果に基いてセールスフォース内のレコードを作成/更新するケースが多々あります。
しかしながら、同じトランザクション内で DML(Insert/Update/Upsert/Delete)発行後にコールアウトを行なう事はでません。

・解決策

上記の様なケースに対応するためには、トランザクションを分け、DMLを発行する前のトランザクションでコールアウト処理を実行する必要があります。

[Salesforce]INVALID_FIELD_FOR_INSERT_UPDATE, Account: bad field names on insert/update call: AccountId: [ AccountId]

INVALID_FIELD_FOR_INSERT_UPDATE, Account: bad field names on insert/update call:  AccountId: [ AccountId]

上記の解決先を共有します。

public void syncContact (Contact contact) {
  ...
  ...
                    Contact newContact = new Contact();
                    newContact.Id = id;
                    newContact.IsTarget__c = true;
                    update newContact;

  ...
  ...
}

[Salesforce]Dml操作で成功したレコード取得

Dml操作で成功したレコード取得した例を共有します。

list<RecordType> rList = [Select id 
                                        From RecordType 
                                        Where sObjectType = 'Account' and DeveloperName = 'PersonAccount'];

system.debug('rList:'+rList);

List<Account> accs = new List<Account>();
for(integer i=0; i<10; i++){
    Account acc = new Account();
    acc.LastName = 'test' + i;
    acc.RecordTypeId = rList.get(0).id;
   accs.add(acc);
    system.debug('acc:'+acc);
}
insert accs;

List<SObject> accList = new List<SObject>();
accList = [select id, LastName From Account];
if(accList.size() > 0){
    system.debug('accList.size():'+accList.size());
    Set<Id> updatedIds = new Set<Id>();
    List<SObject> updatedObjs = new List<SObject>();
    Database.SaveResult[] srList = Database.update(accList, false);
    for (Database.SaveResult sr : srList) {
        if (sr.isSuccess()) {
            // Operation was successful, so get the ID of the record that was processed
            System.debug('Successfully inserted account. Account ID: ' + sr.getId());
            updatedIds.add(sr.getId());
        }
        else {
            // Operation failed, so get all errors                
            for(Database.Error err : sr.getErrors()) {
                System.debug('The following error has occurred.');                    
                System.debug(err.getStatusCode() + ': ' + err.getMessage());
                System.debug('Account fields that affected this error: ' + err.getFields());
            }
        }
    }
    if(updatedIds.size() > 0){
        for(SObject obj : accList){
            if(updatedIds.contains(obj.Id)){
                System.debug('obj.Id:'+obj.Id);
                updatedObjs.add(obj);
            }
        }
    }

}

[Salesforce]スケジュールバッチエラー時メール送信

[Salesforce]スケジュールバッチエラー時メール送信

global class TestBatch implements Database.Batchable<sObject>{

    global Database.querylocator start(Database.BatchableContext BC){
            return Database.getQueryLocator('SELECT Id FROM Account');
    }

    global void execute(Database.BatchableContext BC, List<sObject> scope){
        throw new MyException('test');
    }

    global void finish(Database.BatchableContext BC){
        AsyncApexJob a = [SELECT Id, Status, NumberOfErrors, JobItemsProcessed,
                          TotalJobItems, CreatedBy.Email
                          FROM AsyncApexJob WHERE Id =
                          :BC.getJobId()];
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        mail.setToAddresses(new String[]{'mokamoto@salesforce.com'});
        mail.setReplyTo('noreply@salesforce.com');
        mail.setSenderDisplayName('Batchプロセス');
        mail.setSubject('Batch完了');
        mail.setPlainTextBody('Batch完了しました。エラー' + a.NumberOfErrors +'件');
        Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });

    }    
    class MyException extends Exception{}
}

[Salesforce]必須チェック範囲

Salesforceの必須チェック範囲について共有します。

1.項目設定で必須にした場合

必須チェック範囲:

ページレイアウトからデータ登録・更新

データローダからデータ登録・更新

Apexクラスからデータ登録・更新

2.ページレイアウトで必須にした場合

必須チェック範囲:

ページレイアウトからデータ登録・更新

[Salesforce]スケジュールバッチのトランザクション処理順

スケジュールバッチのトランザクション処理順について共有します。

例えば、10件のデータを1トランザクション毎2件ずつ処理するようになります。

その処理は直列で実行されます。

以下の例で確認できます。

global class SampleBatch implements Database.Batchable<sObject> {
  
  // The batch job starts
  global Database.Querylocator start(Database.BatchableContext bc){
    String query = 'SELECT Id, Name FROM Account LIMIT 100';
    return Database.getQuerylocator(query);
  } 
  
  // The batch job executes and operates on one batch of records
  global void execute(Database.BatchableContext bc, List<sObject> scope){
    System.debug(LoggingLevel.INFO, '>>> execute start at ' + DateTime.now().format('yyyy/MM/dd hh:mm:ss'));
    Long startTime = DateTime.now().getTime();
    Long finishTime = DateTime.now().getTime();
    
    while ((finishTime - startTime) <= 2000) {
      //sleep 2s
      finishTime = DateTime.now().getTime();
    }
    
    System.debug(LoggingLevel.INFO, '>>> execute end at ' + DateTime.now().format('yyyy/MM/dd hh:mm:ss'));
  }
  
  // The batch job finishes
  global void finish(Database.BatchableContext bc){
    AsyncApexJob job = [SELECT Id, Status FROM AsyncApexJob WHERE Id = :bc.getJobId()]; 
    System.debug(LoggingLevel.INFO, '>>>> finish ' + job.Status);
  }
}

バッチ実行

Integer BATCH_SIZE = 2;
SampleBatch sb = new SampleBatch();
Database.executeBatch(sb, BATCH_SIZE);

[Salesforce]@RemoteAction

Salesforceの @RemoteAction について共有します。

特徴

・ JavaScriptからApexクラスの処理を実行できます。

・ actionFunctionと同じような機能ですが、こちらはJavaScript内で処理の戻り値を使用できます。

例えば取引先取得処理を実行して取得した取引先リストを使用した処理を行うことができます。

サンプルコード

・Apexクラス

 global with sharing class SampleRemoteController {
    @RemoteAction
    global static String setString(String str) {
        return  '----- ' + str + ' -----';
    }
    
    @RemoteAction
    global static List<sObject> exequery(String str){
        return Database.query(str);
    }
} 

・Visualforceページ

 <apex:page controller="SampleRemoteController">
    <apex:form >
        <!-- @RemoteActionSample:StringSet -->
        <apex:commandButton value=" String " onClick="return  setString('Yaho');" />
         
        <!-- @RemoteActionSample:SOQLGet -->
        <apex:commandButton value=" GetAcc " onClick="return getAcc();" />
        <hr/>
        <div id="output">Output</div>
    </apex:form>

    <script type="text/javascript">
        /*
         * @RemoteActionSample
         * StringSet
         */
        function setString(str) {
            {!$RemoteAction.SampleRemoteController.setString}(str, function(result, event){
                if(event.status) {
                    document.getElementById("output").innerHTML = result;
                }
            });
            return false;
        }
        
        /*
         * @RemoteActionSample
         * SOQLAccountGet
         */
        function getAcc() {
            var query = 'select Id,Name from Account limit 10';
            {!$RemoteAction.SampleRemoteController.exequery}(query, function(result, event){
                if(event.status) {
                    var names = '';
                    for (var i = 0; i < result.length; i++) {
                        names = names + result[i].Name + ' | ';
                    }
                    document.getElementById("output").innerHTML = names;
                }
            });
            return false;
        }
    </script>
</apex:page>