2011-01-21

Force.com : Apex で DML 処理 - insert

 
Apex で DML 処理 - insert
  • Ex. 取引先(Account)に 1 レコードを追加したい
  • Ex. 取引先(Account)に複数レコードを追加したい



○ 取引先(Account)に 1 レコードを追加したい

Account account = new Account(Name='foo');
try {
    insert account;
} catch (DmlException e) {
    System.debug('***** NG : ' + e);
}

Account account = new Account(Name='foo');
try {
    Database.SaveResult sr = Database.insert(account);
} catch (DmlException e) {
    System.debug('***** NG : ' + e);
}



○ 取引先(Account)に複数レコードを追加したい

Account[] accounts = new Account[]{new Account(Name='foo'), new Account(Name='boo'), new Account(Name='bar')};
try {
    insert accounts;
} catch (DmlException e) {
    System.debug('***** NG : ' + e);
}
※ 1 件でも insert に失敗場合、全レコードが rollback される

Account[] accounts = new Account[]{new Account(Name='foo'), new Account(Name='boo'), new Account(Name='bar')};
try {
    Database.SaveResult[] srs = Database.insert(accounts);
    // ↑と同値:Database.SaveResult[] srs = Database.insert(accounts, true);
} catch (DmlException e) {
    System.debug('***** NG : ' + e);
}
※ 1 レコードでも insert に失敗場合、全レコードが rollback される

Account[] accounts = new Account[]{new Account(Name='foo'), new Account(Name='boo'), new Account(Name='bar')};
try {
    Database.SaveResult[] srs = Database.insert(accounts, false);
} catch (DmlException e) {
    System.debug('***** NG : ' + e);
}
※ insert に成功したレコード: commit、insert に失敗したレコード: rollback、として扱われる



● Database.SaveResult

  • Database.Error[] Database.SaveResult#getErrors() : エラーメッセージとステータスコードを取得。
  • ID Database.SaveResult#getId() : Id を取得。値が入っている場合は insert に成功。値が空の場合は insert に失敗。
  • Boolean Database.SaveResult#isSuccess() : 成功した場合は true。それ以外の場合は false。



◇ 確認環境

  • Salesforce - Developer Edition - API バージョン 20.0



◇ 参考

 

JavaScript : Cookie でボタンの表示/非表示を制御したい

 
Cookie でボタンの表示/非表示を制御したい
  • Ex. 10 日以内に押下したボタンは表示しない



とか、まったくそんな気はなかったのだけれども、メモ。
ブラウザ依存の制御ってどこまで許容されるのだろかとかいつも思う。



○ 10 日以内に押下したボタンは表示しない

<html>
<head>
<script type="text/javascript" language="javascript">
<!--
var ar = new Array('a','b','c','d','e','f','g','h');

function isCookie(key){
    key += '=';
    s=document.cookie.indexOf(key);
    if(s != -1){
        return true;
    }
    return false;
}
function setCookie(key){
    if(key != null){
        var d = new Date();
        d.setDate(d.getDate() + 10);
        document.cookie = key + "=" + escape('true') + ";expires=" + d.toGMTString();
        return true;
    }
    return false;
}
function clearCookie() {
    for(i=0; i<ar.length; i++){
        if(isCookie(ar[i])){
            document.cookie = ar[i] + "=" + "xx; expires=Tue, 1-Jan-1980 00:00:00;";
        }
    }
}

function init(){
    for(i=0;i<ar.length;i++){
        if(isCookie(ar[i])){
            document.getElementById(ar[i]).style.display = 'none';
        }else{
            document.getElementById(ar[i]).style.display = '';
        }
    }
}
//-->
</script>
</head>
<body onload="init();">
<form>
<div id="a"><input type="button" style="width:80px;" onclick="javascript:setCookie('a');location.reload();" value="a" /></div>
<div id="b"><input type="button" style="width:80px;" onclick="javascript:setCookie('b');location.reload();" value="b" /></div>
<div id="c"><input type="button" style="width:80px;" onclick="javascript:setCookie('c');location.reload();" value="c" /></div>
<div id="d"><input type="button" style="width:80px;" onclick="javascript:setCookie('d');location.reload();" value="d" /></div>
<div id="e"><input type="button" style="width:80px;" onclick="javascript:setCookie('e');location.reload();" value="e" /></div>
<div id="f"><input type="button" style="width:80px;" onclick="javascript:setCookie('f');location.reload();" value="f" /></div>
<div id="g"><input type="button" style="width:80px;" onclick="javascript:setCookie('g');location.reload();" value="g" /></div>
<div id="h"><input type="button" style="width:80px;" onclick="javascript:setCookie('h');location.reload();" value="h" /></div>
<div id="z"><input type="button" style="width:80px;" onclick="javascript:clearCookie();location.reload();" value="clear" /></div>
</form>
</body>
</html>



◇ 確認環境

  • Google Chrom 8.0.552.237
  • IE 7.0.5730.13
 

2011-01-19

Force.com : Apex で DML 処理 - savepoint と rollback

 
Apex で DML 処理 - savepoint と rollback
  • Ex. 取引先(Account)に 1 レコードを追加後、なかったことにしたい



○ 取引先(Account)に 1 レコードを追加後、なかったことにしたい

Savepoint sp = Database.setSavepoint();

Account a = new Account(name='foo');
insert a;

// 追加されていることを確認
System.assertEquals('foo', [SELECT id, Name FROM Account WHERE id = :a.id].Name);

Database.rollback(sp);

// rollback されていることを確認
System.assertEquals(new sObject[]{}, [SELECT Name FROM Account WHERE id = :a.id]);
System.Savepoint Database.setSavepoint()

Returns a savepoint variable that can be stored as a local variable, then used with the rollback method to restore the database to that point.
If you set more than one savepoint, then roll back to a savepoint that is not the last savepoint you generated, the later savepoint variables become invalid. For example, if you generated savepoint SP1 first, savepoint SP2 after that, and then you rolled back to SP1, the variable SP2 would no longer be valid. You will receive a runtime error if you try to use it.
References to savepoints cannot cross trigger invocations, because each trigger invocation is a new execution context. If you declare a savepoint as a static variable then try to use it across trigger contexts you will receive a runtime error.
You can only set five savepoints in all contexts, that is, in triggers, anonymous blocks, WSDL methods or unit tests. You will receive a runtime error if you try to set additional savepoints.

  • Database.setSavepoint()
    • セーブポイントを設定する
    • 先に SP1 を生成し、その後で SP2 を生成したときに、SP1 までロールバックを行うと、SP2 は使えなくなる。使うと runtime error が発生する

void Database.rollback(System.Savepoint sp)

Restores the database to the state specified by the savepoint variable. Any emails submitted since the last savepoint are also rolled back and not sent.

Note
Static variables are not reverted during a rollback. If you try to run the trigger again, the static variables retain the values from the first run.

You can only restore the database using rollback 20 times in all contexts, that is, in triggers, anonymous blocks, WSDL methods or unit tests. You will receive a runtime error if you try to rollback the database additional times.

  • Database.rollback(System.Savepoint sp)
    • 引数のセーブポイントまでロールバックを行う
    • 20 回くらいロールバックできる?それ以上は runtime error が発生する?(かなり適当)



◇ その他

  • TODO:気が向いたらセーブポイントを設定できる制限あるか探す



◇ 確認環境

  • Salesforce - Developer Edition - API バージョン 20.0



◇ 参考

 

2011-01-11

Force.com : 行動を作成/更新したとき、Chatter で任命先(所有者)のユーザにメッセージを送りたい

 
行動で任命先(所有者)以外のユーザが行動を作成/更新したときに、Chatter で任命先(所有者)のユーザにメッセージを送りたい。



... なんて、まったく思っていない。
副産物の記念に。



◆ トリガー

trigger t on Event (after insert, after update) {
    List<FeedPost> list = new FeedPost[0];
    for (Event e : Trigger.new) {
        if (e.getSObjectType().getDescribe().isFeedEnabled() && UserInfo.getUserId() != e.OwnerId) {
            FeedPost p = new FeedPost();
            p.type = 'LinkPost';
            p.ParentId = e.OwnerId;
            p.LinkUrl = '/' + e.id;
            p.Title = (e.Subject == '') ? 'no-title' : e.Subject;
            p.Body = '下記の 行動 を' + ((Trigger.isInsert) ? '作成した.' : '更新した.');
            list.add(post);
        }
    }
    if (list.size() > 0) {
        insert list;
    }
}
  • Schema.DescribeSObjectResult#isFeedEnabled()
    • Chatter が有効か判断する(?)
    • API version 19.0 以上より実装



◇ 確認環境

  • Salesforce - Developer Edition - API バージョン 20.0



◇ 参考

 

Force.com : 行動を作成したとき、自動的にフォローするようにしたい

 
行動を作成したとき、任命先(所有者)のユーザが作成した行動を自動的にフォローするようにしたい。



... いや、そんなに思ってはいない。
事の発端は、ヘルプの



行動の詳細の表示

行動の更新とコメントの表示 (Salesforce Chatter)

メモ : ほかのレコードとは異なり、作成した行動または ToDo は Salesforce Chatter では自動フォローされません。

自分が所有するレコードの自動フォロー

ToDo と行動は例外として、自分が所有するレコードは自動的にフォローされます。つまり、そのレコードの項目が変更された場合、更新が Chatter フィードに表示されます。




だった。
Google 先生に聞いてみると Chatter 早見表 (pdf) 発見。 EntitySubscription オブジェクト なるものが記載されていたので ... 以下、下記に続く。



◆ トリガー

trigger t on Event (after insert) {
    List<EntitySubscription> list = new EntitySubscription[0];
    for(Event e : Trigger.new) {
        list.add(new EntitySubscription(ParentId=e.Id, SubscriberId=e.OwnerId));
    }
    insert list;
}
  • EntitySubscription オブジェクト
    • 項目・ParentId : フォローされるユーザまたはレコードの ID
    • 項目・SubscriberId : フォローするユーザの ID



◇ 確認環境

  • Salesforce - Developer Edition - API バージョン 20.0



◇ 参考