編集に関する質問(FireDAC)
FAQ(FireDAC) への移動
このトピックでは、データの編集に関係する質問と回答の一覧を扱います。
Q1: "[FireDAC][DApt]-400. 更新コマンドで [1] 件ではなく [0] 件のレコードを更新しました" とはどういう意味ですか。
A: このエラーが発生するのは、たいてい、FireDAC に float/double/single/date/datetime/time などのテーブル フィールドが含まれていて、WHERE 句で精度が失われる可能性がある場合です。アプリケーションでパラメータに値を代入するときに、精度が失われる可能性があります。その結果、WHERE 句でレコードが返されなくなります。
FireDAC では、UpdateOptions.UpdateMode に応じて WHERE 句にそれらのフィールドが含められることがあります。場合によっては、upWhereKeyOnly でこのエラーが発生することがあります。upWhereKeyOnly を指定していても、FireDAC が upWhereAll を使用する可能性があります。それは、主キー フィールドが定義されていない場合です。次のいずれかに該当する場合は、主キー フィールドが定義されない可能性があります。
- FetchOptions.Items に fiMeta が含まれていない
- SQL 内のテーブルに主キーが定義されていない
- UpdateOptions.KeyFields が空である
- どの TField の ProviderFlags にも pfInKey が含まれていない
一部の DBMS(SQL Server、PostgreSQL)では、テーブルのトリガでデータを変更していることが原因になっている場合もあります。SQL Server では、トリガの先頭に SET NOCOUNT ON を追加してください。PostgreSQL では、UpdateOptions.CountUpdatedRecords を False に設定してください。
Q2: TFDUpdateSQL を使用しなければならないのはどのような場合でしょうか。
A: FireDAC では、元の SQL コマンドが単純な SELECT であるか、JOIN を含む SELECT で 1 つのテーブルが主キー フィールドを保持している場合に、改訂した SQL コマンドを自動生成します。そのため、TFDUpdateSQL を使用するかどうかは任意です。TFDUpdateSQL が必要なのは次の場合です。
- 元の SQL コマンドが SELECT コマンドではない(たとえば、結果セットを返すストアド プロシージャなど)
- 元の SELECT コマンドが主キーを保持していない(たとえば、複数のテーブルを結合している、DISTINCT 句や GROUP BY 句が含まれているなど)
- アプリケーションで非標準の更新 SQL コマンドが必要である(たとえば、アプリケーションでストアド プロシージャ呼び出しを使って更新をポストしているなど)
Q3: FDUpdateSQL の SQL 内でマクロを使用することはできますか。
A: 以下のコードを使用します。
FDUpdateSQL1.Commands[arInsert].MacroByName('MacroName').Value := 'value';
Q4: CachedUpdates モードで ApplyUpdate を複数回呼び出すと、挿入済みのレコードをもう一度ポストしようとするのはなぜですか。
A: ApplyUpdate を呼び出した後で、CommitUpdates を呼び出す必要があります。これを呼び出すと、内部キャッシュからすべての変更が削除されます。
Q5: マスタ TFDQuery のスクロールやポストが行われた後で、詳細 TFDQuery を最新状態に更新しないようにするにはどうすればよいでしょうか。
A: 方法は 2 つあります。
- 独自にマスタ詳細リンケージを実装します。そのためには、TDataSource.OnDataChange イベント ハンドラを追加する必要があります。これが "標準" の方法です。
- 一元キャッシュ更新を使用します。
Q6: データベースから削除しないまま、データセット レコードを削除するにはどうすればよいでしょうか。
A: 内部データセット データ記憶域を直接操作することができます。これには、TFDDataSet.Table プロパティからアクセスできます。たとえば、インデックスが 3 の行を削除するには、次のようにします。
FDQuery1.Table.Rows[3].Free;
FDQuery1.UpdateCursorPos;
FDQuery1.Resync([]);
たとえば、現在のレコードを削除するには、次のようにします。
FDQuery1.UpdateCursorPos;
FDQuery1.GetRow.Free;
FDQuery1.UpdateCursorPos;
FDQuery1.Resync([]);
そして、最後に CachedUpdates モードを使用します。データセットをキャッシュ更新モードに設定してから、レコードを削除して CommitUpdates を呼び出します。
Q7: FireDAC を使用して ATable.UpdateToDataset(BTable , 'mykey', [mtufEdit, mtufAppend]) を作成するにはどうすればよいでしょうか。
A: 以下のオプションで TFDDataSet.CopyDataSet メソッドを呼び出してください。
- [coAppend] - ASource のすべてのレコードを(そのまま)追加します。
- [coEdit] - キー値が既に存在するレコードだけを編集します。
- [coAppend, coEdit] - キー値が既に存在するレコードは編集し、キーが存在しないレコードは追加します。
Q8: ftGUID フィールドに値を割り当てるにはどうすればよいでしょうか。
A: 以下のコードを使用します。
(AMemTable.FieldByName('Field1') as TGUIDField).AsGuid := aGUID;
Q9: データセット フィールドのデフォルト値を指定するにはどうすればよいでしょうか。
A: 式を TField.DefaultExpression プロパティに割り当てます。
Q10: TField.DefaultExpression プロパティは TField.CustomConstraint と同じようにサポートされているでしょうか。また、式の効果はフィールドのデフォルト値として記述されるのでしょうか。
フィールドが通常の結果セット フィールドの場合にはそのとおりです。フィールドが fkInternalCalc の場合には、DefaultExpression の結果がフィールド値として使われ、他の計算フィールドと同じように更新されます。
Q11: {fn DAYOFMONTH({fn CURDATE()})} という式は正しいでしょうか。
A: 正しくありません。その式では FireDAC エスケープ関数を使用しています。エスケープ関数がサポートされるのは SQL コマンド内だけで、式ではサポートされません。制約やデフォルト値式などの式では、次のように、FireDAC 式評価モジュールでサポートされている関数と構文を使用する必要があります。
DAYOFMONTH(CURDATE())
また、FireDAC エスケープ関数を使用するには、アプリケーションに uADStanExprFuncs ユニットをインクルードする必要があります。
Q12: データセットの論理値フィールドのデフォルト値を指定するにはどうすればよいでしょうか。
A: データセット フィールドのデフォルト値を指定するには、必要な式を TField.DefaultExpression プロパティに割り当てます。
論理値フィールドにデフォルト値を割り当てるには、False の名前として、F、FA、FAL、FALS、FALSE のいずれかの文字列を使用します。True の場合も同様です。
Q13: TField.CustomConstraint の割り当てが正しく動作しません。どこが間違っているのでしょうか。
Q: 次のコードで制約を追加しようとしています。
FDQuery.FieldByName('FIELD_NAME').CustomConstraint := 'FIELD_NAME > 1';
FDQuery.UpdateConstraints;
FDQuery.Table.Constraints.Check(FDQuery.GetRow(), rsModified, ctAtEditEnd);
しかし、うまく動作せず、例外も発生しません。
A: それで問題ありません(後で説明します)。
Q: しかし、
FDQuery.Constraints.Add.CustomConstraint := 'FIELD_NAME > 1';
FDQuery.UpdateConstraints;
FDQuery.Table.Constraints.Check(FDQuery.GetRow(), rsModified, ctAtEditEnd);
このコードは正しく動作します。なぜでしょうか。
A: これも問題ありません。
Q: 厳密に、ctAtEditEnd と ctAtColumnChange はどのような意味でしょうか。
A: これらの列挙型では、FireDAC が制約を確認しなければならないイベントを、次のように指定しています。
- ctAtEditEnd - Post が呼び出された
- ctAtColumnChange - フィールド値が変更された
説明しましょう。
FDQuery.FieldByName('FIELD_NAME').CustomConstraint := 'FIELD_NAME > 1';
このコードでは、フィールドレベルの制約を追加しています。この制約の確認が行われるのは ctAtColumnChange イベントのときだけです。
FDQuery.Constraints.Add.CustomConstraint := 'FIELD_NAME > 1';
このコードでは、レコードレベルの制約を追加しています。この制約の確認が行われるのは ctAtEditEnd イベントのときだけです。