NHibernate, проверка логики и AutoDirtyCheck - PullRequest
2 голосов
/ 25 августа 2009

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

Я использую 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, который является оболочкой для ModelState в контроллере.

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


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

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

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

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

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


Так как это решить?

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

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

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

Ответы [ 5 ]

2 голосов
/ 27 августа 2009

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

0 голосов
/ 23 октября 2009

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

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

0 голосов
/ 23 октября 2009

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

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

0 голосов
/ 26 августа 2009

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

0 голосов
/ 25 августа 2009

Лично я вызываю свой код проверки в mvc в defaultmodelbinder по умолчанию. Моя модель представления (опубликованные данные) проверяется, прежде чем я что-то с ней сделаю. Я использую один класс валидатора для каждой задачи валидации.

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);
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...