2011-07-17 6 views
0

私は、検証を追加しようとしているEntity Frameworkモデルを持っていますが、ここではちょっとしたキャッチ22で自分自身を見つけました。プロパティ検証が別のプロパティ値に依存する場合、メタデータを使用してEntity Framework 4モデルを検証する方法

私は...

[MetadataType(typeof(cmsNodeMetadata))] 
public partial class cmsNode : IDataErrorInfo 
{ 
    ... Code .... 


    #region IDataErrorInfo 

    private readonly Dictionary<string, string> _errors = new Dictionary<string, string>(); 
    private readonly Entities _db = new Entities(); 
    public string this[string columnName] 
    { 
     get 
     { 
      if (_errors.ContainsKey(columnName)) 
       return _errors[columnName]; 
      return string.Empty; 
     } 
    } 

    public string Error { get; private set; } 

    partial void OnNameChanging(string value) 
    { 
     var valueIsUnique = (from n in _db.cmsNodes 
          where n.ParentId == ParentId 
           && n.Name.Trim().ToLower() == value.Trim().ToLower() 
          select n.Name).Count() == 0; 

     if (!valueIsUnique) 
     { 
      _errors.Add("Name", "The name must be unique"); 
     } 
    } 

    #endregion 

} 

を次のようになり、別のファイル内のエンティティ生成されたモデルに関連する部分クラスを持っている...と私は作品別のクラスでの検証を追加しましたすばらしいです。

public class cmsNodeMetadata 
{ 
    [StringLength(150), Required] 
    [Display(Name = "Name")] 
    public string Name; 
} 

私はMVC 3と協力し、このクラスを使用して、私のコントローラは、このようになります...このクラスを使用しています

[HttpPost] 
public ActionResult Edit(cmsNode cmsnode) 
{ 
    if (ModelState.IsValid) 
    { 
     var obj = _db.cmsNodes.Single(c => c.Id == cmsnode.Id); 
     obj.Name = cmsnode.Name; 
     obj.Alias = cmsnode.Name.Slugify(150); 
     _db.SaveChanges(); 
     return Content(Boolean.TrueString); 
    } 
    return Content("Please review your form"); 
} 

私の見解は次のようになります...

@model Project.com.Admin.Models.cmsNode 

@using (Ajax.BeginForm("Create", "Node", null, new AjaxOptions 
{ 
    UpdateTargetId = "create-message", 
    InsertionMode = InsertionMode.Replace, 
    HttpMethod = "POST", 
    OnSuccess = "createSuccess" 
}, new { @id = "createNodeForm" })) 
{ 
    @Html.ValidationSummary(true) 
    <div id="create-message" class="error invisible"></div> 
    <fieldset> 
     <legend>Create New Navigation Tree Node</legend> 
     <div class="editor-label"> 
      @Html.LabelFor(model => model.Name) 
     </div> 
     <div class="editor-field"> 
      @Html.EditorFor(model => model.Name) 
      @Html.ValidationMessageFor(model => model.Name) 
     </div> 
     @Html.HiddenFor(model => model.ParentId) 
     @Html.HiddenFor(model => model.Alias) 
    </fieldset> 
} 

さて、ここに問題があります。私は、名前が同じParentIdを持つ他のノードによって既に取得されていないことを確認するこの(cmsNode)クラスにカスタム検証を追加する必要があります。

これを行うには、ParentIdという名前のインスタンスメンバーでハンドルを取得する必要があります。残念ながら、私はcmsNodeMetadataクラスから検証しているインスタンスでハンドルを取得する方法を理解できません。

私は自分のcmsNodeクラスのNameプロパティのonChangingメソッドをオーバーライドし、そこに検証を追加することでアプローチを変更しようとしましたが、別の問題が発生しました。検証のオーバーライドメソッドを使用してnameプロパティを確認することはできますが、Nameプロパティのnull値以外のエンティティモデルは存在しないため、名前がビューから元に戻ったときに例外が発生します。ビューの内容は、マイコンの入力パラメータのモデルタイプに変換されます。

次に、MetadatatTypeとonChangingの両方の検証メソッドを併用してみましたが、onChangingメソッドは無視されています。

私は次のように、この問題を解決できることを理解:

  • IはFormCollectionコレクション、DTOオブジェクトにコントローラの戻り型を変更し、又は直接入力プロパティを定義し、利用し、その後、作成することができ私はnull値をチェックした後、コントローラ内のオブジェクトは正常です。

何か不足していると思いますか? ValidationAttributesを使用してプロパティを検証し、重複する名前を確認する方法はありますか?私の見解からヌルスが戻ってくるのを防ぐことはできますか?エンティティフレームワークのonChangingメソッドで、検証がうまく行かない場合にメンバが設定されないようにするには、Cancelオプションがありません。なぜですか?ご協力いただきありがとうございます!

答えて

0

クロスエンティティの検証は、その責任ではないため、エンティティ自体の一部ではありません。そのため、エンティティまたはそのエンティティに配置されたバリデータがこの検証を行うことは期待できません。エンティティがこの検証を行わない別の理由は、クエリとエンティティ(POCO)を作成するためにコンテキストが必要であり、コンテキストに依存してはいけないということです。

誰がその検証を担当していますか?アプリケーションアーキテクチャに応じて、エンティティ自体が有効になると、IsValidブロック内で呼び出される個別のメソッドが呼び出されます。このメソッドはEFを使用し、同じ名前が存在するかどうかを照会します。ドメイン駆動型設計に近い場合、検証は親にあり、その子が同じ名前を持たないことを検証します(つまり、子をロードすることを意味します)。

+0

コントローラにクロスエンティティ検証を置くことをお勧めしますか?これはうまくいくでしょう... if(ThatNameAlreadyExists(cmsnode)){ModelState.AddModelError( "Name"、 "既にその名前のノードがあります"); } '私のModelState.IsValidチェックの前にそのトリックを行う必要があります。 –

関連する問題