NHibernate,验证逻辑和AutoDirtyCheck

时间:2009-08-25 19:11:11

标签: c# asp.net-mvc nhibernate

以下是我的情景:

我正在使用nhibernate,在IHttpModule中打开和关闭会话(PreRequestHandlerExecute和PostRequestHandlerExecute)。

Ninject负责在我的所有存储库中注入我的会话,我对它非常满意。

现在假设对我的一个实体进行更新(代码简化):

控制器:

User user = _userService.GetUser(id);
user.Name = "foo";
user.Email = "foo@bar.com";
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正在执行验证逻辑并在IValidationDictionary中插入任何错误,该IValidationDictionary是控制器中ModelState的包装。

到目前为止一切顺利,我得到了所有错误(如果有的话),我可以在视图中显示它们。


问题出现了:

当我尝试保存错误的用户(例如没有名称)时,永远不会调用_rep.Update(user)方法,但用户仍然会被保存。

谷歌周围知道了nhibernate AutoDirtyCheck,这意味着如果我在内存中更改一个实体,它将自动保存在数据库中。

非常强大的功能我同意,但由于我的会话是在PostRequestHandlerExecute中提交的,所以无论如何我的无效实体都被保存了,这是我不想要的。

我尝试使用unhaddins删除此行为,它有效,但是当我只保存父级时,我的子对象不会自动保存:(


那怎么解决呢?

在调用_userService.GetUser(id)之前,使ValidadeUser公开并验证副本吗?

将验证逻辑放在别处吗?也许在实体类本身? (我喜欢这么多分开!)。

提前多多感谢。

5 个答案:

答案 0 :(得分:2)

仅供参考 - 您可以将Nhibernate会话FlushMode属性设置为FlushMode.Never,以完全控制NHibernate何时刷新数据库更新。可能是你可以作弊,如果一个动作没有被授权 - 永远不会进行刷新,当响应结束时,nhibernate会话就会死掉(如果会话没有消失,你真的应该驱逐修改过的对象,那么)

答案 1 :(得分:0)

就个人而言,我在defaultmodelbinder中调用mvc中的验证码。在我完成任何操作之前,我的viewmodel(发布的数据)已经过验证。我为每个验证问题使用一个验证器类。

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);
        }
    }
}

答案 2 :(得分:0)

我自己没有尝试过,但首先想到的是分离无效的用户对象。如果您不执行另一个将检索相同用户的查询,则也会返回相同的,现在无效的对象。

答案 3 :(得分:0)

Fabio Maulo有一个非常好的写作/解决方案

http://fabiomaulo.blogspot.com/2009/03/ensuring-updates-on-flush.html

答案 4 :(得分:0)

您可以使用ISession.Evict(obj)从会话中删除该对象,这将阻止它自动保留。需要注意的一点是,这会使对象出现瞬态,并且尝试加载任何延迟初始化的子对象(通常是集合)将导致NH抛出LazyInitializationException。

ETA:我刚刚看到你对Maurice的评论,你无法直接访问ISession。我手动将ISession注入存储库/服务类,因为WinForms需要它。在ISession中有几种方法我不得不不时访问,特别是Evict,Merge和Lock。我会公开ISession或一个包装器,以便你可以使用Evict。