9

C# から SQL Server データベースにデータを挿入するストアド プロシージャを呼び出しています。一意の列など、テーブルにいくつかの制約があります。現在、次のコードがあります。

try
{
   // inset data
}
catch (SqlException ex)
{
    if (ex.Message.ToLower().Contains("duplicate key"))
    {

        if (ex.Message.ToLower().Contains("url"))
        {
            return 1;
        }

        if (ex.Message.ToLower().Contains("email"))
        {
            return 2;
        }
    }

    return 3;
}

C#またはストアプロシージャにデータを挿入する前に、列が一意かどうかなどを確認するか、例外を発生させて上記のように処理することをお勧めしますか? 私は上記のファンではありませんが、この分野でのベストプラクティスを探しています.

4

5 に答える 5

8

私はデータベースの制約を最後の手段と考えています。(つまり、データの整合性を維持するためのバックアップ方法として、必ずスキーマに存在する必要があります。)ただし、データベースに保存する前に、データは実際に有効である必要があります。他の理由がない場合は、無効な入力に関するフィードバックを提供することがUIの懸念事項であり、データの有効性エラーが層スタック全体を毎回上下することはないはずです。

さらに、制約を使用して簡単に表現できないデータの形状について、さまざまな種類のアサーションを作成する必要があります。(たとえば、注文の状態遷移。「注文はSHIPPEDからのみ進むことができますPAID」またはより複雑なシナリオ。)つまり、手続き型言語ベースのチェック、さらに多くのビジネスロジックを複製するチェック、および次に、それらにある種のエラーコードも報告させ、スキーマ定義ですべてのデータ検証を行うためだけに、アプリにさらに複雑なものを含めます。

検証は、UIに関係し、モデルスキーマに結合されているため、アプリに配置するのは本質的に困難ですが、私はUIの近くで検証を行う側に向きを変えます。

于 2013-03-22T18:45:39.407 に答える
3

ここに2つの質問があり、これが私の見解です...

データベースの制約は適切ですか?大規模なシステムの場合、それらは不可欠です。ほとんどの大規模システムには複数のフロントエンドがあり、中間層またはUIデータチェックロジックを共有できる互換性のある言語であるとは限りません。また、Transact-SQLまたはPL/SQLのみのバッチプロセスがある場合もあります。フロントエンドでチェックを複製することは問題ありませんが、マルチユーザーアプリで真に一意性をチェックする唯一の方法は、レコードを挿入してデータベースの内容を確認することです。外部キー制約についても同じです。挿入/更新/削除を試みるまで、本当にわかりません。

例外のスローを許可する必要がありますか、それとも戻り値を置き換える必要がありますか?質問のコードは次のとおりです。

    try
    {
       // inset data
    }
    catch (SqlException ex)
    {
        if (ex.Message.ToLower().Contains("duplicate key"))
        {
            if (ex.Message.ToLower().Contains("url"))
            {
                return 1; // Sure, that's one good way to do it
            }
            if (ex.Message.ToLower().Contains("email"))
            {
                return 2; // Sure, that's one good way to do it
            }
        }
        return 3; // EVIL! Or at least quasi-evil :)
    }

呼び出し側プログラムが実際に戻り値に基づいて動作することを保証できるのであれば、とはあなたの判断に任せるのが最善だと思いreturn 1ますreturn 2。私はこのような場合(たとえばDuplicateEmailException)にカスタム例外を再スローすることを好みますが、それは私だけです-戻り値もトリックを行います。結局のところ、コンシューマークラスは、戻り値を無視できるのと同じくらい簡単に例外を無視できます。

私は反対ですreturn 3。これは、予期しない例外(データベースのダウン、接続不良など)が発生したことを意味します。ここに不特定のエラーがあり、あなたが持っている唯一の診断情報はこれです:「3」。行を挿入しようとしたが、システムが「3」と言ったという質問をSOに投稿するとします。お知らせ下さい。それは数秒以内に閉じられます:)

データクラスで例外を処理する方法がわからない場合、データクラスのコンシューマーがそれを処理する方法はありません。この時点で、あなたはかなり困惑しているので、エラーをログに記録してから、「予期しないエラー」メッセージを表示して、可能な限り正常に終了します。

予期しない例外について少し怒鳴ったことは知っていますが、プログラマーがデータベースの例外を続かしただけで、予期しないことが発生したときにアプリがサイレントに失敗するか、ダウンストリームで失敗し、診断情報がゼロになるというサポートインシデントを処理しすぎました。非常にいたずらな。

于 2013-03-22T19:22:02.557 に答える
2

私は、SQL Server にデータをスローして制約がエラーを発生させる前に、違反の可能性をチェックするストアド プロシージャを使用したいと考えています。この理由は、パフォーマンスに関連しています。

プログラムですべてを実行できるため、データベース層での制約は不要であると主張する人もいます。重複を検出するために C# プログラムだけに頼らない理由は、人々が C# プログラムを介さずにデータに影響を与える方法を見つけるからです。後で他のプログラムを紹介するかもしれません。独自のスクリプトを作成したり、データベースと直接やり取りしたりする人がいる場合があります。テーブルはビジネス ルールを尊重しないため、本当にテーブルを保護しないままにしておきますか? また、C# プログラムが単にテーブルにデータを投げて、最善を期待するべきではないとも思います。

ビジネス ルールが変更された場合、本当にアプリ (または複数のアプリすべて) を再コンパイルする必要がありますか? それは、データベースがどれだけ適切に保護されているか、およびビジネス ルールが変更される可能性と頻度に依存すると思います。

于 2013-03-22T19:11:24.830 に答える
0

私はこのようなことをしました:

public class SqlExceptionHelper
{
    public SqlExceptionHelper(SqlException sqlException)
    {
        // Do Nothing.
    }

    public static string GetSqlDescription(SqlException sqlException)
    {
        switch (sqlException.Number)
        {
             case 21:
                 return "Fatal Error Occurred: Error Code 21.";
             case 53:
                 return "Error in Establishing a Database Connection: 53.";
             default
                 return ("Unexpected Error: " + sqlException.Message.ToString());
         }
     }
}

これにより、再利用が可能になり、SQL からエラー コードを取得できるようになります。

次に、実装するだけです:

public class SiteHandler : ISiteHandler
{
     public string InsertDataToDatabase(Handler siteInfo)
     {
          try
          {
              // Open Database Connection, Run Commands, Some additional Checks.
          }
          catch(SqlException exception)
          {
             SqlExceptionHelper errorCompare = new SqlExceptionHelper(exception);
             return errorCompare.ToString();
          }
     }
}

次に、一般的な発生に対していくつかの特定のエラーを提供しています。しかし、前述のように; データベースに入力する前に、データをテストしたことを確認する必要があります。そうすれば、不一致の制約が表面化することも、存在することもありません。

それがあなたを良い方向に向けてくれることを願っています。

于 2013-03-22T18:51:51.163 に答える
0

何をしようとしているかによって異なります。考慮すべき点:

  • エラーをどこで処理しますか? できるだけデータに近いものをお勧めします。
  • エラーについて誰に知らせたいですか? ユーザーは、「その ID を既に使用している」ことを知る必要がありますか?

また、-制約は良い場合があります-その点に関するミリムースの答えに100%同意しません-つまり、私はこのようにする必要があります/より良いパフォーマンスの理想に同意します-しかし、実際には、そうしない場合開発者/qcを制御できます。特に、データベースを爆破する可能性のあるルールを適用する場合(または、レポートなどの依存オブジェクトを壊す場合)、重複したキーがどこかに現れた場合、それに対するいくつかの障壁が必要です(たとえば) 重複したキー エントリ。

于 2013-03-22T18:51:53.427 に答える