ケンが言うように、サンプルコードなしであなたを助けるのは難しいです。ですから、私はあなたの質問に直接答えることはできませんが、いくつかの指針があれば、あなたはそれを自分で理解することができるかもしれません。だから私はあなたに魚を教えることを試みるつもりです。;)
私はDelphi3および6のTClientDataSetについてかなりの経験がありますが、状況がそれほど変わったとは思えません。さらに、正しい方向にキックスタートするためのテクニックにさらに焦点を当てます。
まず、VCLコードでブレークポイントを取得できるように、必ずDebugDCUでコンパイルしてください。そのコードを読んでステップスルーすることを恐れないでください-それは学ぶための素晴らしい方法です。さらに、Borland / CodeGear/Embarcaderoの醜い栄光の中での間違いを見ることができます。
すでに例外の停止が有効になっていると想定しています(したがって、特にAVエラーが発生していることがわかっているのはなぜですか)。
あなたのテストをしてください。AVを入手すると、おそらくDbClient.pas(またはおそらく下位レベルのユニットの1つ)に表示されます。
コールスタックを調べて、 try..exceptブロックのtry部分内にいる場所を探します。このブロックは、例外を飲み込むか、別のハンドラーに短絡してから飲み込みます。
注:DbClient.pasには、次の不正なコードのかなりの数のインスタンスが散らばっています。
except //swallowing or squashing exceptions is
end; //very dangerous and should be avoided.
except
//short-circuiting to Application.HandleException (usually informs the user)
//but is not much better. The point is the rest of the program up the
//call-stack remains blissfully unaware that something went wrong.
Application.HandleException(Self);
Action := raAbort;
end;
サイドコメント:ボーランドがそれをしたからといって、それが良い習慣であるという意味ではありません。あなたと他の多くの人はこれを持っており、これによって燃やされるでしょう。
あなたがそれを見つけたら、あなたはそこの半分にいます。これで、AVについて通知されない理由がわかりました。
これで、その呼び出しスタックの一部を形成するコード内のどこかに、エラーの処理方法の手がかりが得られます。また、VCLコードの少し前にブレークポイントを設定して、例外に至るまでの一連のイベントを確認することもできます。AV(Access Violation)について具体的に言及したので、 nilを参照するオブジェクトを探します。
問題の原因の1つの例は、D5DbClient.pasの次のスニペットにあります。
FOnReconcileError(DataSet, E, UpdateKind, Action);
finally
E.Free;
end;
except
Application.HandleException(Self);
Action := raAbort;
end;
上記から、特定の状況ではOnReconcileErrorイベントハンドラーを実装する必要があることがわかります。これがないと、dllは上記のコードスニペットへのコールバックを与えられず、多くのエラーがカーペットの下で静かに蹴られ、頭を悩ませることになります。
TClientDataSetでの私の経験では、TClientDataSetを「正しく」使用するためにやらなければならない小さな余分なことがいくつかありました。これは、ドキュメントでは特に明白ではありませんでした。やるべきことをすべて理解したら、それらを行う方法の例は少し良くなりました。
残念ながら、私の記憶はこれらすべてのものが何であったかについて少し曖昧です。したがって、これは非常に大まかなガイドであり、おそらくかなり欠落しています。
- OnReconcileErrorイベントハンドラーの使用を検討してください。
- UpdateProviderオブジェクトの実装を検討してください。
- これをメモリ内データセットとして使用するとおっしゃっていたので、おそらくCreateDataSetを正しく使用しています。しかし、私が正しく覚えていれば、フィールドを指定するための2つのオプションがあり、より細かい詳細属性のいくつかは少し厄介でした。
- 無関係なヒント:文字列フィールドの長さに注意してください。TClientDataSetは、短い文字列と同様の方法でメモリを群がらせていました(そして今でもそうなる可能性があります)。
編集
質問の追加情報に基づいて、上記の手法を使用すると、次のメソッドからEDatabaseErrorがスローされます。
procedure TIntegerField.SetAsString(const Value: string);
var
E: Integer;
L: Longint;
begin
if Value = '' then Clear else
begin
Val(Value, L, E);
if E <> 0 then DatabaseErrorFmt(SInvalidIntegerValue, [Value, DisplayName]);
SetAsInteger(L);
end;
end;
呼び出しスタックの上位にあると、問題を解決する方法を示唆する次のメソッドが得られます。
procedure TField.SetEditText(const Value: string);
begin
if Assigned(FOnSetText) then FOnSetText(Self, Value) else SetText(Value);
end;
また、KeyPressまでのコールスタックをたどると、データセットやグリッドコードがまったく含まれていないことに気付くでしょう。
OnPostエラーのエラーを処理しようとしても機能しなかった理由は、レコードを投稿する試みに近づいていないためです。フィールド検証エラーが発生し、それを処理する場所がフィールド上にあります。
エラーを解決する方法のヒントに戻ると、フィールドにOnSetTextイベントを実装する必要があります。
ただし、そうしないことをお勧めします。すぐに使用できる動作は完全に受け入れられます。ユーザーは、何が間違っていたかを説明するエラーメッセージを受け取り、それを修正して再試行する機会を得ます。気が変わったら、Escapeキーを押して編集をキャンセルできます。