newSobjectしてVisualforceに使ったらSObject row does not allow errorsが出る話
こんばんは
Visualforceで項目セットを使ってまともな画面を開発する際、
ちょっと困ったことがあったけど、ググっでも出てこなかったので、
書いておくことにします。
条件
- 初期値反映したいのもあって、sObjectType.newSobjectを使っている
- Visualforceで入力項目にinputFieldを使っている
こんなとき、
- 必須入力項目に入力がない
- 入力項目の型にそぐわない入力値(数値項目に漢字とか)がある
という状態でフォームのsubmitが呼ばれると、
SObject row does not allow errors
が出ます。それはもう、淡白な画面に。
原因
今回のエラーメッセージは、トリガでaddErrorを呼んだりするときに
起きやすい(ふつうはそんなコード書かないけど)もので、
その辺は検索すればたくさん出てくるので端折ります。
この問題は、別のタイミングでも発生して、
SObject型のインスタンスからaddErrorが呼ばれても発生します。
で、先ほど書いた、以下の状態
- 必須入力項目に入力がない
- 入力項目の型にそぐわない入力値(数値項目に漢字とか)がある
では、フォームのSubmitが行われ、Viewstateの復元時にエラーとして
自動検知され、内部的にaddErrorが該当のインスタンスから
呼ばれることになります。
※このへん、JSFじゃないから自分でコントロールできなくて嫌だ
例えば、こんなコードです
サンプル(例だからAccountで書いた)
public Account obj { get; set; }
obj = ( Account ) Account.sObjectType.newSobject(recordTypeId,true);
このobjをVisualforceに使ってはいけません。
よく見ればわかりますが、newSobjectはSObject型インスタンスを返すのであって、
Accountを返してくれるわけではありません。
なので、件名のようなエラーが発生することになります。
正常系ではうまーく動くんですけどね。
また、シンプルに obj = new Account();
って書けばうまく動くんですけど、これだと初期値の反映がうまくいきません。
C++のdynamic_castのダウンキャストみたいに、いっそnullを返してくれたほうが
マシなのですが、それが出来ない言語事情だから仕方ない…けど、
エラーからも少しわかりにくいし、気付くのに遅れるのがちょっと腹が立つ。
対処法
今度真面目に調べますけど、以下のような感じにすればうまく動きます。
かなり適当なので、最適解ではないと信じたい。
Account obj = (Account)JSON.deserialize(JSON.serialize(
Account.sObjectType.newSobject(recordTypeId,true)),Account.class);
それではまたー