CTOになりたい

CTOになりたかったけどなれなかったから一回なってみたいブログ

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);

それではまたー