Нужно ли загружать / получать объект перед SaveOrUpdate в Nhibernate?
В моем приложении ASP.NET MVC я отделил модель домена от модели представления.
Я преобразую свою сущность в объект модели представления, чтобы я мог "кормить" свои представления только необходимыми данными (для этого я использовал valueinjecter).
В процессе сохранения мой контроллер возвращает объект viewmodel, преобразует его в объект модели домена и пытается сохранить его с помощью SaveOrUpdate. Я заметил, что если я пытаюсь обновить существующую запись, Nhibernate рассматривает ее как новый объект и вызывает INSERT, даже если моя сущность имеет правильный идентификатор.
Я не загружал (Get/Load) объект прежде, потому что я хотел бы избежать повторного сопоставления всех полей снова.
Что-то я делаю не так? Какой лучший способ достичь этого?
***** - ОБНОВИТЬ - ***
Мой контроллер получает User (ViewModel), проверяет его и пытается сохранить его через сервисный уровень как объект:
public ActionResult Edit(Guid id, Models.User User)
{
...
var user = new Domain.User();
user.InjectFrom(User);
user.SetId(id);
user = this._SecurityService.SaveUser(user);
}
Это сервис:
public Domain.User SaveUser(Domain.User User)
{
bool Result = false;
if (this._ValidationEngine.IsValid(User))
{
using (_UnitOfWork)
{
if (User.Code != Guid.Empty)
{
var user = this._UserRepository.Load(User.Code);
user.InjectFrom(User);
User = this._UserRepository.Update(user);
}
else {
User = this._UserRepository.Save(User);
}
Result = _UnitOfWork.Commit();
}
}
return (User);
}
У меня есть беспокойство по поводу того, что мне приходится трансформировать мою модель / сущность столько раз. Теперь, когда я пытаюсь сохранить нового пользователя, я получаю это сообщение: строка была обновлена или удалена другой транзакцией (или сопоставление несохраненного значения было неправильным)
Возможно, это в некоторой степени связано с тем, что Дарин говорил мне.
Есть ли лучшие способы сделать то, что я пытаюсь сделать?
ОБНОВИТЬ
Я заметил, что ошибка "Строка была обновлена или удалена..." вызвана тем, что у меня есть версия, определенная для моих сопоставлений. Что я могу понять, так это то, что мне нужен идентификатор и версия, соответствующие сущности, которую я хочу обновить.
Я хотел бы понять, как другие люди делают эти вещи с DDD + ASP.NET MVC + NHibernate???
РЕШЕНИЕ
У всех моих сущностей есть определенная версия (я забыл сказать, извините):
<version name="Version" type="System.Int32" unsaved-value="0">
<column name="Version" not-null="true" />
</version>
Как объяснил Айенде, Nhibernate пытается обновить мою сущность с помощью запроса:
UPDATE Table SET field1 = 'bla', Version = (y+1) WHERE id = x AND Version = y
где у должна быть версия моей сущности. Поскольку я не заполнял свою сущность версией, она генерировала исключение StaleObjectException.
Я добавил поле версии в мою модель просмотра. Я сохраняю его в скрытом поле зрения вместе с идентификатором.
Мой контроллер теперь получает модель представления с идентификатором и версией. Я вставляю эти поля в мою сущность домена и позволяю хранилищу сохранить ее (я не перезагружаю свою сущность):
User = this._UserRepository.Update(user);
Если я получаю исключение StaleObjectException, это означает, что кто-то еще обновил строку БД, и я предоставлю пользователю некоторую обратную связь.
2 ответа
Поскольку у вас уже есть идентификатор и, следовательно, вы знаете, что это обновление, используйте session.Update
вместо SaveOrUpdate
,
За SaveOrUpdate
чтобы работать как положено, вам нужно явно указать unsaved-value
атрибут на вашем <id>
отображение. Так, например, у вас будет:
<id unsaved-value="0" ...
а затем выдать SaveOrUpdate
вызов модели, в которой свойству Id присвоено значение, отличное от 0
и это будет UPDATE
вместо INSERT
, Поэтому, чтобы ответить на ваш вопрос, нет, вам не нужно вручную выдавать SELECT
до UPDATE
, SaveOrUpdate
должен сделать это за кадром.