NHibernate, проверка логики и AutoDirtyCheck

2

Вот мой сценарий:

Я использую nhibernate, открывая и закрывая сеанс в IHttpModule (PreRequestHandlerExecute и PostRequestHandlerExecute).

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 выполняет логику проверки и вставляет любую ошибку в документ IValidationDictionary, который является оболочкой для ModelState в контроллере.

Пока все хорошо, я получаю все ошибки (если есть), и я могу показать их в представлении.


Здесь возникает проблема:

Когда я пытаюсь сохранить пользователя с ошибкой (нет имени, например), метод _rep.Update(пользователь) никогда не вызывается, но пользователь все равно сохраняется.

Приближение к нему, по-моему, известно, что AutoDirtyCheck nhibernate означает, что если я изменю объект в памяти, он будет сохраняться автоматически в базе данных.

Очень мощная функция, которую я согласен, но так как мой сеанс завершен в PostRequestHandlerExecute, мой недействительный объект все равно сохраняется, чего я не хочу.

Я попытался удалить это поведение, используя unhaddins, он работал, но тогда мои дочерние объекты не сохраняются автоматически, когда я сохраняю только родительский: (


Итак, как это решить?

Сделать ValidadeUser общедоступным и проверять копию перед вызовом _userService.GetUser(id)?

Поместите логику проверки в другое место? Может быть, в классе сущности? (Мне это очень нравится!).

Большое спасибо заранее.

Теги:
asp.net-mvc
nhibernate

5 ответов

2
Лучший ответ

FYI - вы можете установить для свойства Nushernate Session FlushMode значение FlushMode.Never, чтобы полностью контролировать, когда NHibernate будет обновлять базу данных. Возможно, вы можете обманывать и если действие не разрешено - никогда не делайте флеш, и сеанс nhibernate будет умирать, когда ответ завершен (если сеанс не исчез, вы действительно должны выселить измененный объект, tho)

0

У Фабио Моло очень хорошая запись/решение

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

0

Вы можете использовать ISession.Evict(obj), чтобы удалить объект из сеанса, и это предотвратит его автоматическое сохранение. Следует отметить, что это делает объект кратковременным и пытается загрузить любые ленивые инициализированные дочерние объекты (как правило, коллекции) заставит NH вызывать исключение LazyInitializationException.

ETA: Я просто прочитал ваш комментарий Морису, что вы не можете напрямую обращаться к ISession. Я вручную внедряю ISession в классы репозитория/службы, потому что это необходимо для WinForms. В ISession существует несколько методов, с которыми мне приходилось время от времени получать доступ, особенно Evict, Merge и Lock. Я бы разоблачил ISession или обертку, чтобы вы могли использовать Evict.

0

Я не пробовал это сам, но первое, что приходит на ум, - это отсоединить недопустимый пользовательский объект. Если вы не выполните другой запрос, который будет получать один и тот же пользователь, он также вернет тот же объект, теперь недействительный.

  • 0
    Это бы сработало, но мой сервис не знает, что такое session.evict () :(
  • 0
    Как он уже знает о GetUser () и Update (), что-то вроде CancelChanges () не кажется неуместным.
0

Лично я вызываю свой код проверки в mvc в defaultmodelbinder. Моя 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);
        }
    }
}
  • 0
    Мне нравится ваше решение. Я хотел бы видеть больше мнений все же. Если никто не отвечает в течение одного или двух дней, вы получаете V :)
  • 0
    Человек, проблема. При этом я не могу получить ошибку дублированного объекта таким же образом (как попытка обновить пользователя с существующим именем пользователя). Как вы справляетесь с этим?
Показать ещё 5 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню