logo

サイト内検索
ココログ最強検索 by 暴想

最近のトラックバック

無料ブログはココログ

« javaScriptからWebApiで公開Apexにアクセス | トップページ | Facebook APIで出来ない事:Pageによる他のPageへの投稿 »

ApexCode:楽観的排他制御について

SalesForceで排他制御……? え?!    となる方も居るでしょう。


SalesForceではたしかに排他制御を標準でサポートしています。
ただしそれは標準の画面利用に限り、VisualForce等自分で書いたコード上Updateする場合は効かないようです。

なので、VisualForceでUpdateを利用する場合は、自分で排他制御を組み込む必要があります。


方法としては二通りあり、
1.レコードSelect時に for UPDATE オプションを取り付け、悲観的排他制御を用いる
  >Locking Statements
2.Update直前にDB上から対象レコードをSelectし、LastModifyDateと比較を図る
  ※今回はこちらを利用します





楽観的排他制御の基本的流れは次のようになります。


  1.DBから更新対象のレコード取得
  2.レコードを編集
  3.更新ボタンをおし、処理スタート
  4.1のレコードを再取得
  5.1と2のレコードのLastModifyDateを比較
  6A.同一  :updateに2のレコードをセット
  6B.差異あり:updateを流さず戻る

6Bのエラー時、弊社では「エラーページへ遷移する」という仕様にしています。

 

    //Update実装例
    public Pagereference goUpdate(){
        PageReference pr = checkSave(Sobject);
        if(pr != null){
            return pr;
        }
    }


    //楽観的排他制御付更新。エラーが発生した場合はエラーページへのPagereferenceが返る
    public static Pagereference checkSave(SObject so){
        if(so==null){
            return null;
        }
        String tblname = so.getSObjectType().getDescribe().getLocalName();
        String ql = 'select id,LastModifiedDate,LastModifiedBy.Name from ' +
            tblname + ' where id =\'' + so.id + '\'';
        Sobject[] wksos = Database.query(ql);
        if(wksos.isEmpty()){
            //削除エラー
            //Page.ConcurrencyErrorは、SalesForceエラーページのソースを利用して作ったVisualForce。
            return Page.ConcurrencyError;  //排他エラー:誰かが削除していた
        } else if(wksos[0].get('LastModifiedDate')!=so.get('LastModifiedDate')){
            //makeErrPrはエラー生成用のメソッド。後述
            return makeErrPr(wksos[0]);    //排他エラー:レコードが編集されていた
        }
        update so;  //問題なければUpdate
        return null;
    }


    //エラー情報を添付したエラーページへの遷移情報作成。
    private static Pagereference makeErrPr(SObject wkso){
        SObject anone =  wkso.getSObject('LastModifiedBy');
        Pagereference pr = Page.ConcurrencyError;
        Map

pmap = pr.getParameters();
        pmap.put('retUrl','/'+wkso.get('id'));        //戻り先のURL
        pmap.put('unmae',(String)anone.get('Name'));  //先にレコードを書き換えたユーザーの名前
        pmap.put('uid',(String)anone.get('id'));      //先にレコードを書き換えたユーザーのID
        return pr;
    }

-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
<エラー表示用VisualForce:ConcurrencyError>
<apex:page controller="ConcurrencyError">
<apex:outputPanel rendered="{!uid!=null}">
<!--更新エラー-->
<table cellspacing='10'>
  <tbody><tr>
    <td><span style='font-weight: bold; font-size: 12pt;'>変更を保存できません</span></td>
  </tr>
  <tr>
    <td>
編集していたレコードは、編集セッション中に<a href='/{!uid}'>{!unmae}</a>によって変更されました。
<br/><br/>
        もう一度編集する前に、<a href='{!retUrl}'>レコードを再表示</a>してください。
    </td>
  </tr>
</tbody></table>
</apex:outputPanel>
<apex:outputPanel rendered="{!uid==null}">
<!--削除エラー-->
<table cellspacing="10">
  <tbody><tr>
    <td><span style="font-weight: bold; font-size: 12pt;">レコードは削除されました。</span></td>
  </tr>
  <tr>
    <td>
アクセスを試みた情報は削除されました。このレコードを削除したユーザは、ごみ箱から情報を復活させることができます。 削除データはごみ箱の中に 30 日間保管されます。(一部の情報を除く。)
    </td>
  </tr>
</tbody></table>
</apex:outputPanel>
</apex:page>

<コントローラ>
public with sharing class ConcurrencyError {
  public ConcurrencyError(){
    Map

pmap = System.currentPageReference().getParameters();
    this.retUrl = pmap.get('retUrl');
    this.unmae = pmap.get('unmae');
    this.uid = pmap.get('uid');
  }
    public String retUrl { get; set; }
    public String unmae { get; set; }
    public String uid { get; set; }
    static testMethod void ConcurrencyErrorTest() {
      ConcurrencyError cr=new ConcurrencyError();
    }
}





また複数オブジェクトを別個に、かつ同一処理内でUpdateする場合、
ロールバックを考慮して以下のように実装します。

    //SObject1とSObject2の場合
    //Update実装例
    public PageReference goUpdate(){
        System.Savepoint sp = Database.setSavepoint();
        //SObject1のレコード処理
        PageReference pr = checkSave(SObject1);
        if(pr != null){
            return pr;
        }
        //SObject2のレコードを処理
        //ここで失敗したとき、RollBack処理をしないとSObject1の処理が確定してしまう。
        PageReference pr = checkSave(SObject2);
        if(pr != null){
            Database.rollback(sp);
            return pr;
        }
        return null;
    }

このような具合に実装すれば、自作のVisualForce&Updateでも排他制御が働きます。

では良きSalesForceライフを。

« javaScriptからWebApiで公開Apexにアクセス | トップページ | Facebook APIで出来ない事:Pageによる他のPageへの投稿 »

Salesforce」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック

この記事のトラックバックURL:
http://app.f.cocolog-nifty.com/t/trackback/1482716/40698329

この記事へのトラックバック一覧です: ApexCode:楽観的排他制御について:

« javaScriptからWebApiで公開Apexにアクセス | トップページ | Facebook APIで出来ない事:Pageによる他のPageへの投稿 »