本稿は、Scott Guthrie氏のブログを、氏の許可を得て、翻訳、転載したものです。米Microsoft社の副社長で、ASP.NETやSilverlightの開発チームを統率する氏のブログでは、次期製品を含む最新の技術をいち早く紹介しています。
原典:Class-Level Model Validation with EF Code First and ASP.NET MVC 3
EFコードファーストとASP.NET MVC 3でクラスレベルのモデル検証
今週初めに、データチームが、新しいEntity FrameworkコードファーストライブラリのCTP5ビルド版をリリースしました。
数日前、新しいCTP5ビルド版で導入された改善点について、ブログの中で、いくつか話しました。その中の1つに、モデル上でDataAnnotation検証属性を、自動的に強制実行するというサポートがありました。これにより、モデル層内のプロパティレベルの検証ロジックを、非常に簡単に有効化できるようになります。
[Required]、[Range]、[RegularExpression](これらはすべて.NET 4にビルトインされています)のような検証属性をモデルクラスに適用すると、データベースに永続化される前に、そのモデルプロパティが必ず有効な状態になります。また、独自の検証属性(この素晴らしい[CreditCard]validatorの様に)を作成して、自動的にEFコードファーストで強制実行することもできます。これにより、モデル上でプロパティの値を非常に簡単に検証できるようになります。前回のブログ投稿で、このコードサンプルをいくつか紹介しました。
IValidatableObjectを使用したクラスレベルのモデル検証
DataAnnotation属性により、モデルクラス上の個々のプロパティの値が簡単に検証できます。
『EFコードファーストは、複数のプロパティの値に渡って必要な検証ルールに対して、モデルオブジェクト上にクラスレベルの検証メソッドを実装する方法もサポートしているのか?』という質問を、何回か受けましたが、それはサポートしています。これを行う簡単な方法は、IValidatableObjectインターフェイスをモデルクラス上に実装します。
IValidatableObject.Validateメソッド
以下は、Productモデルクラス上に独自の検証ルールを2つ実装するために、IValidatableObjectインターフェイス(.NET 4のSystem.ComponentModel.DataAnnotations名前空間にビルトインされている)を使用した例です。この2つのルールにより、次のことができません。
- 停止状態にあるProductは新しくオーダーできない
- 在庫が100以上あるものは新しくオーダーできない
Productクラス上でIValidatableObjectインターフェイスを実装し、そのValidateメソッドを実装することで、これらのビジネスルールを強制実行します。
IValidatableObject.Validateメソッドは、複数のプロパティに渡る検証ルールを適用でき、複数の検証エラーを戻すことが可能です。戻ってきたそれぞれのValidationResultは、エラーメッセージと、違反の原因であるプロパティ名のオプション一覧(これはUIでエラーメッセージを表示する時に便利です)も、どちらも提供できます。
自動的な検証の強制実行
EFコードファースト(CTP5以降)では、IValidatableObjectインターフェイスを実装しているモデルオブジェクトが保存された時、自動的にValidateメソッドを発生させるようになりました。これを発生させるためにコードを書く必要はありません。現在これはデフォルトで有効化されています。
この新しいサポートは、以下のコード(上記のビジネスルールに1つ違反します)が、NorthwindのDbContext上の『SaveChanges』メソッドを呼び出したときに、例外を自動的に投げる(そしてトランザクションを中止する)ということを意味します。
検証の例外を反応的に処理する以外に、EFコードファーストは、事前に検証エラーをチェックすることも可能です。CTP5以降で、DbContextベースクラス上の『GetValidationErrors』メソッドを呼び出して、作業中のモデルオブジェクトにある検証エラーの一覧を取得できます。GetValidationErrorsは、DataAnnotation属性を通じて生成されたものなのか、またIValidatableObject.Validate実装により生成されたものなのかに関わらず、すべての検証エラーの一覧を返します。
以下は、GetValidationErrorsメソッドを使用して、SaveChangesを呼び出そうとする前に、事前にエラーをチェック(そして処理)する例になります。