以下是我的情景:
我正在使用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公开并验证副本吗?
将验证逻辑放在别处吗?也许在实体类本身? (我喜欢这么多分开!)。
提前多多感谢。
答案 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。