Рассмотрим простой код редактирования / обновления:
public ActionResult Edit(int id)
{
return View(db.Foos.Single(x => x.Id == id));
}
public ActionResult Update(Foo changed)
{
Foo foo = db.Foos.Single(x => x.Id == changed.Id);
foo.P1 = changed.P1;
db.SubmitChanges();
}
Что я на самом деле пытаюсь сделать, это отправить:
UPDATE [dbo].[Foos]
SET [P1] = @p1
WHERE ([Id] = @p0)
Но на самом деле мы получаем 2 дБ вызовов:
// Read current db object
SELECT [t0].[Id], [t0].[P1]
FROM [dbo].[Foos] AS [t0]
WHERE [t0].[Id] = @p0
// Submit changes
UPDATE [dbo].[Foos]
SET [P1] = @p2
WHERE ([Id] = @p0) AND ([P1] = @p1)
Запрос UPDATE гарантирует, что объект не изменился со времени последнего запроса, но на самом деле это бесполезно в нашем контексте. Действительно, база данных может быть изменена до того, как пользователь отправит форму, и наш код не обнаружит никаких проблем. Но если Foo был изменен после того, как мы прочитали его в действии Update, но перед SubmitChanges, мы получим ChangeConflictException (это может привести к путанице).
Чтобы такие обновления (проверка исходных значений в БД) имели смысл, мы должны отправлять исходный объект Foo назад и вперед по HTTP.
public ActionResult Update(Foo original, Foo changed)
{
Foo foo = db.Foos.Attach(changed, original);
db.SubmitChanges();
}
В этом случае мы будем обнаруживать изменения в дБ, пока пользователь вводил значения.
Но если меня не волнуют параллельные изменения, разве оригинальные методы обновления не выглядят неправильно?