.NET Framework アプリケーションのデータセット内のデータを検証する

Note

データセットと関連クラスは、アプリケーションがデータベースから切断されている間にアプリケーションがメモリ内のデータを操作できるようにする、2000 年代初期からのレガシ .NET Framework テクノロジです。 テクノロジが特に役立つのは、ユーザーがデータを変更し、変更をデータベースに戻して保持できるようにするアプリケーションです。 データセットは非常に優れたテクノロジであることが証明されていますが、新しい .NET アプリケーションでは Entity Framework Core を使用することをお勧めしています。 Entity Framework には、オブジェクト モデルとして表形式データを操作する、より自然な方法が用意されており、よりシンプルなプログラミング インターフェイスが備わっています。

データの検証とは、データ オブジェクトに入力される値が、データセットのスキーマ内の制約に準拠していることを確認するプロセスのことです。 また、検証プロセスでは、これらの値が、アプリケーションに対して設定されている規則に従っているかどうかも確認されます。 データの検証は、基になるデータベースに更新を送信する前に実行することをお勧めします。 そうすることで、エラーを減らせるだけでなく、アプリケーションとデータベースの間で生じる可能性のある、ラウンド トリップの回数も減らせます。

データセットに書き込まれようとしてるデータが有効であるかどうかは、データセット自体に検証チェックを組み込むことによって確認できます。 データセットでは、更新の実行方法 (フォーム内のコントロールによって直接実行されるか、コンポーネント内で実行されるか、またはその他の方法で実行されるか) に関係なく、データを確認できます。 データセットは (データベース バックエンドとは違って) アプリケーションの一部であるため、アプリケーション固有の検証を構築するための論理的な場所となります。

アプリケーションに検証を追加するための最適な場所は、データセットの部分クラス ファイルです。 Visual Basic または Visual C# で、データセット デザイナーを開き、検証を作成する列またはテーブルをダブルクリックします。 このアクションにより、コード ファイルが開き、ここに ColumnChanging または RowChanging イベント ハンドラーを作成できます。

private static void OnColumnChanging(object sender, DataColumnChangeEventArgs e)
{

}

データの検証

データセット内での検証は、次の方法で実現されます。

  • アプリケーション固有の検証を独自に作成して、個々のデータ列の変更時にその値をチェックできるようにする。 詳細については、「方法: 列の変更時にデータを検証する」を参照してください。

  • アプリケーション固有の検証を独自に作成して、データ行全体が変更される際に、データの値をチェックできるようにする。 詳細については、「方法: 行の変更時にデータを検証する」を参照してください。

  • データセットの実際のスキーマ定義の一部として、キー、一意の制約などを作成する。

  • DataColumn オブジェクトのプロパティ (MaxLengthAllowDBNullUnique など) を設定する。

レコードで変更が発生すると、DataTable オブジェクトによっていくつかのイベントが発生します。

  • ColumnChanging および ColumnChanged イベントは、個々の列の変更時と変更後にそれぞれ発生します。 ColumnChanging イベントは、特定の列の変更を検証する場合に便利です。 提案された変更に関する情報は、イベントの引数として渡されます。
  • RowChanging および RowChanged イベントは、行の変更時と変更後にそれぞれ発生します。 RowChanging イベントの方がより一般的です。 これは、行のどこかで変更が発生していることを示すもので、どの列が変更されたかはわかりません。

既定では、列が変更されるたびに、4 つのイベントが発生することになります。 まずは、変更されようとしている列の ColumnChanging および ColumnChanged イベントです。 次に、RowChanging および RowChanged イベントです。 行に対して複数の変更が行われようとしている場合は、各変更に対してイベントが発生します。

注意

データ行の BeginEdit メソッドは、個々の列が変更された後、RowChanging イベントと RowChanged イベントをオフにします。 その場合、イベントは EndEdit メソッドが呼び出されるまで発生しません。その際、RowChanging イベントと RowChanged イベントが 1 回だけ発生します。 詳細については、「データセットの読み込み中に制約をオフにする」を参照してください。

どのイベントを選択するかは、検証をどの粒度で行うかによって決まってきます。 列が変更されたとき、すぐにエラーをキャッチすることが重要な場合は、ColumnChanging イベントを使って検証を作成します。 それ以外の場合は、RowChanging イベントを使用します。その場合、一度に複数のエラーがキャッチされる可能性があります。 また、データが構造化されていて、ある列の値が別の列の内容に基づいて検証される場合は、RowChanging イベント中に検証を実行します。

レコードが更新されると、DataTable オブジェクトによってイベントが発生します。これらに対しては、変更の発生時と発生後に応答することができます。

アプリケーションで型指定されたデータセットが使われる場合は、厳密に型指定されたイベント ハンドラーを作成できます。 これにより、型指定された 4 つのイベント (dataTableNameRowChangingdataTableNameRowChangeddataTableNameRowDeleting、および dataTableNameRowDeleted) が追加されるので、それらに対してハンドラーを作成できます。 これらの型指定されたイベント ハンドラーでは、テーブルの列名を含んだ引数が渡されます。これにより、コードの記述と読み取りが容易になります。

データ更新イベント

event 説明
ColumnChanging 列の値が変更されようとしています。 このイベントでは、行と列、そして提案された新しい値が渡されます。
ColumnChanged 列の値が変更されました。 このイベントでは、行と列、そして提案された値が渡されます。
RowChanging DataRow オブジェクトに対して行われた変更が、データセットにコミットされようとしています。 BeginEdit メソッドを呼び出していない場合は、列が変更されるたび、ColumnChanging イベントの発生直後に RowChanging イベントが発生します。 変更を加える前に BeginEdit を呼び出した場合、RowChanging イベントは、EndEdit メソッドを呼び出したときにのみ発生します。

このイベントでは、行と共に、実行されようとしているアクションの種類 (変更、挿入など) を示す値が渡されます。
RowChanged 行が変更されました。 このイベントでは、行と共に、実行されようとしているアクションの種類 (変更、挿入など) を示す値が渡されます。
RowDeleting 行が削除されようとしています。 このイベントでは、行と共に、実行されようとしているアクションの種類 (削除) を示す値が渡されます。
RowDeleted 行が削除されました。 このイベントでは、行と共に、実行されようとしているアクションの種類 (削除) を示す値が渡されます。

ColumnChangingRowChanging、および RowDeleting イベントは、更新プロセス中に発生します。 これらのイベントは、データを検証したり、その他の種類の処理を実行するために使用できます。 これらのイベント中は更新が処理中であるため、例外をスローして更新を取り消すこともできます。そうすることで、更新が完了するのを防ぐことができます。

ColumnChangedRowChanged、および RowDeleted イベントは、更新が正常に完了したときに発生する通知イベントです。 これらのイベントは、更新が正常に行われた後、さらにアクションを実行する場合に便利です。

列の変更時にデータを検証する

Note

データセット デザイナーでは、データセットに検証ロジックを追加できる、部分クラスが作成されます。 デザイナーによって生成されたデータセットは、部分クラス内のコードを削除したり変更したりするものではありません。

データ列の値が変更される際には、ColumnChanging イベントに応答することで、データを検証することができます。 このイベントが発生すると、現在の列に対して提案されている値を含んだイベント引数 (ProposedValue) が渡されます。 e.ProposedValue の内容に基づいて、次の操作を実行できます。

  • 何もせずに、指示された値を受け入れます。

  • 列変更イベント ハンドラー内から列エラー (SetColumnError) を設定して、提案された値を拒否します。

  • オプションで ErrorProvider コントロールを使用して、ユーザーにエラー メッセージを表示します。 詳細については、「ErrorProvider コンポーネント」を参照してください。

検証は、RowChanging イベント中に実行することもできます。

行の変更時にデータを検証する

検証する各列にアプリケーションの要件を満たすデータが格納されていることを検証するコードを記述できます。 これを行うには、提案された値が受け入れられものである場合に、エラーが含まれていることを示すように列を設定します。 Quantity 列が 0 以下の場合に列エラーを設定する例を次に示します。 行変更イベント ハンドラーは、次のように記述します。

行の変更時にデータを検証するには (Visual Basic)

  1. データセット デザイナーでご自分のデータセットを開きます。 詳細については、「チュートリアル: データセット デザイナーを使用したデータセットの作成」を参照してください。

  2. 検証するテーブルのタイトル バーをダブルクリックします。 この操作により、データセットの部分クラス ファイルに RowChangingDataTable イベント ハンドラーが自動的に作成されます。

    ヒント

    テーブル名の左側をダブルクリックして、行変更イベント ハンドラーを作成します。 テーブル名をダブルクリックすると、名前を編集できます。

    Private Sub Order_DetailsDataTable_Order_DetailsRowChanging(
        ByVal sender As System.Object, 
        ByVal e As Order_DetailsRowChangeEvent
      ) Handles Me.Order_DetailsRowChanging
    
        If CType(e.Row.Quantity, Short) <= 0 Then
            e.Row.SetColumnError("Quantity", "Quantity must be greater than 0")
        Else
            e.Row.SetColumnError("Quantity", "")
        End If
    End Sub
    

行の変更時にデータ検証するには (C#)

  1. データセット デザイナーでご自分のデータセットを開きます。 詳細については、「チュートリアル: データセット デザイナーを使用したデータセットの作成」を参照してください。

  2. 検証するテーブルのタイトル バーをダブルクリックします。 この操作により、DataTable の部分クラス ファイルが作成されます。

    Note

    データセット デザイナーでは、RowChanging イベントのイベント ハンドラーが自動作成されません。 RowChanging イベントを処理するメソッドを作成し、そのイベントをフックするコードをテーブルの初期化メソッドで実行する必要があります。

  3. 部分クラスに次のコードをコピーします。

    public override void EndInit()
    {
        base.EndInit();
        Order_DetailsRowChanging += TestRowChangeEvent;
    }
    
    public void TestRowChangeEvent(object sender, Order_DetailsRowChangeEvent e)
    {
        if ((short)e.Row.Quantity <= 0)
        {
            e.Row.SetColumnError("Quantity", "Quantity must be greater than 0");
        }
        else
        {
            e.Row.SetColumnError("Quantity", "");
        }
    }
    

変更された行を取得する

データ テーブルの各行には、DataRowState 列挙体の値を使ってその行の現在の状態を追跡する、RowState プロパティがあります。 DataSet または DataTableGetChanges メソッドを呼び出すと、データセットやデータ テーブルから変更された行を返すことができます。 データセットの HasChanges メソッドを呼び出せば、GetChanges を呼び出す前に、変更が存在するかどうかを確認できます。

注意

(AcceptChanges メソッドを呼び出して) データセットやデータ テーブルに変更をコミットすると、GetChanges メソッドはデータを返さなくなります。 変更された行をアプリケーションで処理する必要がある場合は、AcceptChanges メソッドを呼び出す前に変更を処理する必要があります。

データセットまたはデータ テーブルの GetChanges メソッドを呼び出すと、変更されたレコードのみを含んだ、新しいデータセットまたはデータ テーブルが返されます。 新しいレコードのみ、または変更されたレコードのみを取得するなど、特定のレコードを取得したい場合は、DataRowState 列挙体の値を GetChanges メソッドへのパラメーターとして渡すことができます。

異なるバージョンの行 (たとえば、行を処理する前の元の値) にアクセスするには、DataRowVersion 列挙体を使用します。

データセットから変更されたすべてのレコードを取得するには

  • データセットの GetChanges メソッドを呼び出します。

    次の例では、changedRecords という新しいデータセットを作成し、dataSet1 という別のデータセットから、変更されたすべてのレコードを設定します。

    DataSet changedRecords = dataSet1.GetChanges();
    

データ テーブルから変更されたすべてのレコードを取得するには

  • DataTable の GetChanges メソッドを呼び出します。

    次の例では、changedRecordsTable という新しいデータ テーブルを作成し、dataTable1 という別のデータ テーブルから、変更されたすべてのレコードを設定します。

    DataTable changedRecordsTable = dataTable1.GetChanges();
    

行が特定の状態にあるすべてのレコードを取得するには

  • データセットまたはデータ テーブルの GetChanges メソッドを呼び出し、DataRowState 列挙値を引数として渡します。

    次の例は、addedRecords という新しいデータセットを作成し、dataSet1 データセットに追加されたレコードのみを設定する方法を示しています。

    DataSet addedRecords = dataSet1.GetChanges(DataRowState.Added);
    

    次の例は、Customers テーブルに最近追加されたすべてのレコードを返す方法を示しています。

    private NorthwindDataSet.CustomersDataTable GetNewRecords()
    {
        return (NorthwindDataSet.CustomersDataTable)
            northwindDataSet1.Customers.GetChanges(DataRowState.Added);
    }
    

DataRow の元のバージョンにアクセスする

データ行を変更すると、データセットにその行の元のバージョン (Original) と新しいバージョン (Current) が保存されます。 たとえば、AcceptChanges メソッドを呼び出す前にレコードの別のバージョン (DataRowVersion 列挙定数で定義) にアクセスし、そのバージョンに応じて変更を処理できます。

Note

別のバージョンの行が存在するのは、その行が編集されてから AcceptChanges メソッドが呼び出されるまでの間です。 AcceptChanges メソッドの呼び出し後は、現在のバージョンと元のバージョンが同じになります。

DataRowVersion 値を列インデックス (文字列である列名) と共に渡すと、その列の特定の行バージョンから値が返されます。 変更された列は、ColumnChanging イベントと ColumnChanged イベントの発生時に識別されます。 検証目的で複数の行バージョンを検査するには、これが最適なタイミングです。 ただし、一時的に制約を中断しているときはこれらのイベントは発生しないため、変更された列をプログラムで識別する必要があります。 Columns コレクションを反復処理し、異なる DataRowVersion 値を比較することにより変更された列を識別できます。

レコードの元のバージョンを取得するには

  • 取得する行の DataRowVersion を渡して列の値にアクセスします。

    次の例は、DataRowVersion 値を使って、DataRowCompanyName フィールドの元の値を取得する方法を示しています。

    string originalCompanyName;
    originalCompanyName = northwindDataSet1.Customers[0]
        ["CompanyName", DataRowVersion.Original].ToString();
    

DataRow の現在のバージョンにアクセスする

レコードの現在のバージョンを取得するには

  • 列の値にアクセスした後、どのバージョンの行を取得するかを示すインデックスに、パラメーターを追加します。

    次の例は、DataRowVersion 値を使って、DataRowCompanyName フィールドの現在の値を取得する方法を示しています。

    string currentCompanyName;
    currentCompanyName = northwindDataSet1.Customers[0]
        ["CompanyName", DataRowVersion.Current].ToString();