2012-02-16 8 views
2

レイヤー間のデータ検証に関する質問があります。例として、Titleという文字列プロパティを持つBookというオブジェクトがあるとします。レイヤー間の検証値の同期化

DBには、Titleの特定の長さがあります。これは、Titleプロパティに格納できる文字の数を指定します。

私は、アプリケーションの各レイヤー間のリクエストを検証しています。そこで、プレゼンテーションレイヤーのユーザー入力を検証し、アプリケーションレイヤーへのサービス呼び出しを検証し、SQLデータベースはデータを挿入しようとする前にそのデータを検証します。

タイトルのプロパティの長さが限られている場合は、各レイヤーでこれを伝える最も良い方法は何ですか。 SQL Serverで長さが40文字を超えることはできないと言われている場合、長さの値を各文字列にハードコードすることなく、他のレイヤーにこれを伝える最も良い方法は何でしょうか。

あなたはこの状況で何をしていますか?

答えて

2

まずオフ:I挿入 にしようとする前に、

SQLデータベースは明らかにデータを検証すること

いいえ、それはしません。パラメータを介して渡す場合、切り捨てられます。直接SQL文を実行している場合、の挿入後にエラーが返されます。言っ

は、我々は属性を経由して私たちのオブジェクトにバリデータを追加し、エンタープライズライブラリの検証は、私たちのDBサーバにデータを渡すためにしようとする前にキックオフしましょう。これにより、プロパティごとに複数の言語でメッセージをカスタマイズすることができます。

例:

using Microsoft.Practices.EnterpriseLibrary.Validation; 
    using Microsoft.Practices.EnterpriseLibrary.Validation.Validators; 

    namespace MyApp.ObjectModel { 
     public class Account { 
     private String _accountNumber = String.Empty; 
     [StringLengthValidator(1, 50, MessageTemplateResourceName="ValidationStringLength", MessageTemplateResoourceType = typeof(MyApp.Properties.ErrorMessages), Tag="Account Number")] 
     public String AccountNumber { 
      get { return _accountNumber; } 
      set { _accountNumber = value; } 
     } 


     protected Validator BuildValidator() { 
      return ValidationFactory.CreateValidator<Account>(); 
     } // method::BuildValidator 


     public String Validate() { 
      Validator internalValidator = BuildValidator(); 
      ValidationResults info = internalValidator.Validate(this); 
      String result = String.Empty; 

      if (!info.IsValid) { 
      foreach(ValidationResult vr in info) { 
       result += vr.Message; 
      } 
      } 
      return result; 
     } // method::Validate 


     public Boolean Save() { 
      if (String.IsNullOrEmpty(Validate()) { 
      // perform the save operation. 
      } else { 
      // do something else, log the message or send it back to the screen or whatever. 
      } 
     } 
     } // class::Account 
    } 

上記のクラスは、エンタープライズライブラリのバリデータを使用して、非常に簡単な例です。これを取り除く主なものはAccountNumberプロパティの属性であり、基本的にアカウント番号は1〜50文字でなければならないと言います。

データを保持するたびに呼び出される基本クラスに、Validate()メソッドを配置しました。また、私たちのvalidateメソッドは、実際にオブジェクトを保存しようとしているものまでフィルタリングするエラーのコレクションを返します。次に、Inversion of Controlパターンを使用して、適切なデータレイヤインターフェイスをオブジェクト自体に渡します。このようにして、オブジェクトのロジックを保存したままで、モッキング機能と永続性メカニズム(データベースサーバ)を自由に交換する機能をサポートしながら、オブジェクトを維持することができます。これは上のコードサンプルでは表現されていません。

基本的にこれは他のすべての層がそれの無知なると、単純に適切な場所(画面上の通常メッセージ領域)にすべてのエラーをフィルタリングすることができますが、私たちはビジネスクラス内検証ロジックを維持することができます。特殊化された検証ロジックがある場合は、カスタムバリデーターを追加し、必要に応じて属性を振りかざすのは簡単です。

最終的なことは、それぞれの層は、データの整合性を確保するために、保存OPの間だけではなく、任意の時点でvalidate()メソッドを呼び出すことができるということです。

+0

ので、どのようにあなたは、このような最大の長さなどの値を扱うん:

は以下のCodePlexからいくつかの実装コードを見たことがありますか?データベースのフィールドの最大長が10の場合、レイヤーに値10をハードコードしますか?または、中央構成を使用していますか? – Chris

+0

@ChrisPaynter:10はクラス定義にベイクされています。すべてのレイヤーは、オブジェクトが有効かどうかを判断するためにオブジェクトに依存します。 – NotMe

+0

ああ、ありがとう。だから私はあなたのために公開const intを使用していると思いますか? – Chris

0

私は私がデータベースを打つ前に、私のエンティティを検証することを可能にするメカニズムを持っていることを好む。(UIとビジネス層に)

はなぜ?

ウェルデータベースは、通常、定義されたスキーマの違反を許容せず、通常はNHibernateやEntity Frameworkなどの永続フレームワークを使用している場合は特に例外が発生します(これらのフレームワークでは通常、仕事のパターンとワンショットですべてのものをしようとし、何かが間違っている場合は、再びそのショットを持つことができる保証はありません:) :)

どのように?ほとんどのソリューションで

これは、メタデータ(XML設定ファイルや.NET属性) を意味し、それはdatabase.MVCフレームワークと同期これらのメタデータは、私の意見ではかなりある箱から出して、このような仕組みを持って行うことを意味cool 私はこのメタデータソリューションの代替手段を見たことがありませんが、データベースの実際のスキーマを使用してその場でメタデータを構築できます。

これらの違反をユーザーに警告するポリシーは異なる場合があります。 何人かが間違っている(フィールドで検証する)と、すべてのデータを提供した後にユーザーに警告する(フォームで検証する)ことを好む人もいますが、両方のケースでモデルを検証するために、このインフラストラクチャはモデルから独立している必要があります。したがって、再利用可能です。

2

私は(つまり、あなたのデシベルに自分のドメインの検証にネクタイ)を正確に何をしますボックスソリューションのうちがあると思います

しかし、いくつかのスマートで私たちはあなたを救う何かを実装することができません余分な作業が必要です。

私は、これはあなたがあなたのアプリケーション層全体でドメインモデルを検証するために使用できる検証クラスを作成することができますFluentValidation

のようなフレームワークを使用して見てお勧めします。

したがって、モデルごとに1つの検証クラスだけが必要です。そして、DBは、そのレベルの問題をあなたに知らせます。

必要に応じて、レイヤーごと、シナリオごとに1つの検証クラスを作成することができます。 [OK]を

using FluentValidation; 

public class CustomerValidator: AbstractValidator<Customer> { 
    public CustomerValidator() { 
    RuleFor(customer => customer.Surname).NotEmpty(); 
    RuleFor(customer => customer.Forename).NotEmpty().WithMessage("Please specify a first name"); 
    RuleFor(customer => customer.Company).NotNull(); 
    RuleFor(customer => customer.Discount).NotEqual(0).When(customer => customer.HasDiscount); 
    RuleFor(customer => customer.Address).Length(20, 250); 
    RuleFor(customer => customer.Postcode).Must(BeAValidPostcode).WithMessage("Please specify a valid postcode"); 
    } 

    private bool BeAValidPostcode(string postcode) { 
    // custom postcode validating logic goes here 
    } 
} 

Customer customer = new Customer(); 
CustomerValidator validator = new CustomerValidator(); 
ValidationResult results = validator.Validate(customer); 

bool validationSucceeded = results.IsValid; 
IList<ValidationFailure> 

failures = results.Errors; 
+0

+1:私と同じ概念ですが、EntLibに代わるものです。 – NotMe

関連する問題