2009-08-25 16 views
2

は、ここに私のシナリオです:NHibernateは、検証ロジックとAutoDirtyCheck

私はopenningとのIHttpModule(PreRequestHandlerExecuteとPostRequestHandlerExecute)でセッションを閉じて、NHibernateはを使用しています。

Ninjectが私のすべてのリポジトリにセッションを挿入してくれてとても満足しています。

は今私のエンティティ(コードが簡素化)のいずれかに更新したとします

コントローラー:

User user = _userService.GetUser(id); 
user.Name = "foo"; 
user.Email = "[email protected]"; 
user.Group = _groupService.GetGroup(idGroup); 
if(_userService.Edit(user)) { 
    RedirectToAction("Index"); 
} 
else { 
    return View(user); 
} 

サービス:

if(ValidateUser(user) { 
    return _rep.Update(user); 
} 
return false; 

のvalidateUserは、検証ロジックを実行し、任意のエラーを挿入していますコントローラ内のModelStateのラッパーであるIValidationDictionaryに格納されます。

これまでのところ、すべてのエラー(もしあれば)が得られ、ビューに表示することができます。ここで


に問題が来る:私は、エラー(たとえば、名前なし)をユーザーに保存しようとすると

、メソッド_rep.Update(ユーザー)が呼び出されることはありませんが、ユーザーが保存されますとにかく

nhibernateのAutoDirtyCheckは、メモリ内のエンティティを変更すると自動的にデータベースに保持されることを意味します。

非常に強力な機能私は同意しますが、私のセッションはPostRequestHandlerExecuteでコミットされているので、私の無効なエンティティはとにかく保存されています。

私はunhaddinsを使用して、この動作を削除しようとした、それが働いていたが、私は親だけを保存するときに、私の子オブジェクトは自動的に保存されていない:(


それを解決するために、どのように?

検証ロジックを別の場所に置いていますか?おそらくエンティティクラス自体にありますか(私は非常に離れているのが好きです)。

ありがとうございます。

答えて

2

FYI - NHibernateがデータベースへの更新をフラッシュするとき、NhibernateセッションのFlushModeプロパティをFlushMode.Neverに設定することができます。あなたが不正行為をする可能性があり、アクションが許可されていない場合 - フラッシュを行わず、応答が終了したときにnhibernateセッションが終了する場合があります(セッションが終了しなかった場合は、実際に修正されたオブジェクトを削除する必要があります)。

0

個人的には、私はmvcでdefaultmodelbinderで自分の検証コードを呼び出します。私のビューモデル(投稿されたデータ)は、何かをする前に検証されます。私は各バリデーションの懸念に対して1つのバリデータクラスを使用します。

public class MyController : Controller 
{ 
    public ActionResult MyActionMethod(UserChangeModel model) 
    { 
    if (!ModelState.IsValid) 
    { 
     return RedirectToAction("Index");  
    } 

    User user = _userService.GetUser(model.Id); 
    user.Name = model.Name; 
    user.Email = model.Email; 
    user.Group = _groupService.GetGroup(model.IdGroup);  
    return View(user); 
    } 
} 

public class MyDefaultModelBinder : DefaultModelBinder 
{ 
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     var boundInstance = base.BindModel(controllerContext, bindingContext); 
     if (boundInstance != null) 
     { 
      var validator = findValidator(bindingContext.ModelType); 
      var errors = validator.Validate(boundinstance); 
      addErrorsToTheModelState(bindingContext, errors); 
     } 
    } 
} 
+0

私はあなたのソリューションが好きです。私はより多くの意見を見たいと思います。 1〜2日で誰も答えなければ、あなたはVを手に入れます:) – andrecarlucci

+0

男、問題です。これにより、既存のユーザー名でユーザーを更新しようとしても、同じ方法で重複したエンティティエラーが発生することはありません。あなたはこれにどのように対処していますか? – andrecarlucci

+0

validator.Validate(object toValidate)(擬似コード)は、渡されたオブジェクトのタイプ(この場合はviewmodel型)に応じて、バリデータクラスインスタンスを作成するバリデータファクトリを呼び出します。バリデータークラスは、バリデーターから継承するクラスです。検証する必要のあるモデルごとに別々のバリデータークラスを作成します。バリデータファクトリは、IoC/Serviceロケータを使用してバリデータクラスのインスタンスを解決します。バリデータークラスにdataacessクラスを挿入して、ユーザー名が存在するかどうかを調べることができます。 – Paco

0

私はこれを自分で試していないが、心に来る最初の事は、無効なユーザーオブジェクトを切り離しています。同じユーザーを取得する別のクエリを実行していない場合は、現在無効な同じオブジェクトも返されます。

+0

動作しますが、私のサービスはsession.evict()が何であるか分かりません:( – andrecarlucci

+0

GetUser()とUpdate()について既に知っているように、CancelChanges()のようなものは、 – Maurice

0

非常に良い過去記事/ソリューションを持っています。注目すべきは、これによりオブジェクトが一時的になり、遅延初期化された子オブジェクト(通常はコレクション)をロードしようとすると、NHがLazyInitializationExceptionをスローすることになります。

ETA:Mauriceにあなたのコメントを読んだだけで、ISessionに直接アクセスすることはできません。私は手作業でISessionをリポジトリ/サービスクラスに注入します。これは、WinFormsに必要なためです。私が時々アクセスしなければならなかったいくつかのメソッド、特にEvict、Merge、Lockは、Sessionにあります。 Evessionを使用できるように、私はISessionまたはラッパーを公開します。

関連する問題