3

こんにちは、TUniQuery を使用して Access DB を更新するこの関数があります。

var
  Res:Boolean;
begin
Res:=false;
  try
  with MyQuery do
  begin
    Active := false;
    SQL.Clear;
    SQL.Add('Update MYTABLE');
    SQL.Add('set username='+QuotedStr(NewUserName));
    SQL.Add(',password='+QuotedStr(NewPassword));
    SQL.Add('where username='+QuotedStr(ACurrentUserName));
    ExecSQL;
    Res:=true;
  end;
  except
  Res:=False;
  end ;
  Result:=Res;
end;

"ExecSQL" が成功したか失敗したかを知るには、Try ... を使用するだけで十分ですか?

または他のより良いアプローチはありますか?

ありがとうございました

4

1 に答える 1

10

例外が発生しない場合は、更新が成功したと見なすことができます。これは、データベースが応答性が高く、構文エラーなしでステートメントを解析および実行したことを意味します。

示されているようなステートメントでは、正確に1 つの行が更新されたことを確認することもできます。

これを確認するには、ステートメントの実行によって影響を受けた行数を返す ExecSQL メソッドの結果に頼ることができます。したがって、コードを次のように変更できます。

begin
  with MyQuery do
  begin
    Active := false;
    SQL.Clear;
    SQL.Add('Update MYTABLE');
    SQL.Add('set username='+QuotedStr(NewUserName));
    SQL.Add(',password='+QuotedStr(NewPassword));
    SQL.Add('where username='+QuotedStr(ACurrentUserName));
    Result := ExecSQL = 1; //exactly 1 row updated
  end;
end;

また、例外を処理するのに適切なサイトではない可能性があるため、無条件の例外ハンドラーを変更し、結果を格納するローカル変数も削除しました。これは実際には必要ないためです。

追加したテキストを読み、質問を再考した後:

"ExecSQL" が成功したか失敗したかを知るには、Try ... を使用するだけで十分ですか?

このルーチンから例外処理とブール値を返すことについて、本当に考えを変える必要があります。例外は、プログラムの例外的およびエラー状況に対処する方法に関するまったく新しい概念として導入されましたが、このまったく新しい (そして IMHO より優れた) アプローチを無効にし、成功または失敗を示す値を返す古い方法に頼っています。

特に、try/exceptionメモリ不足、データベースへの接続が失われたなどのネットワークの問題など、多くの理由で発生する可能性のある例外を強制終了するため、例外を食べるブロックは悪い習慣です。

アプローチを再考し、これらの例外またはエラー条件をアプリケーションの適切なレベルで処理する必要があります。

私のアドバイスは次のとおりです。

  • これを関数からプロシージャに変更すると、新しいコントラクトは次のようになります。成功した場合にのみ戻り、それ以外の場合は例外が発生します。
  • 例外が発生した場合は、ルーチンから飛び出し、その状況を別の場所で処理します
  • 正確に1行が更新されない場合に備えて、独自の例外を発生させます
  • パラメータを使用するようにクエリを変更します (SQL インジェクションを回避します)。

ルーチンは次のようになります。

procedure TMySecurityManager.ChangeUserNameAndPassword();
begin
  MyQuery.SQL.Text := 'Update MYTABLE'
              + '   set username = :NewUserName'
              + '       , password = :NewPassword'
              + ' where username = :username';
  MyQuery.Params.ParamByName('NewUserName').AsString := NewUserName;
  MyQuery.Params.ParamByName('NewPassword').AsString := NewPassword;
  MyQuery.Params.ParamByName('username').AsString := ACurrentUserName;
  if MyQuery.ExecSQL <> 1 then
      raise EUpdateFailed.Create('A internal error occurred while updating the username and password');
  //EUpdateFailed is a hypotetical exception class you defined.
end;
于 2013-01-24T21:57:43.663 に答える