ViewModel Удалить исключение параллелизма не работает - PullRequest
0 голосов
/ 03 апреля 2012

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

На моей странице Index у меня есть кнопка для удаления каждого объекта Vehicle .Нажатие на эту кнопку приводит к Post к действию Delete.Вот действие Удалить:

[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(VehicleIndexViewModel vehicleIndexViewModel)
{
  try
  {
    Vehicle vehicle = db.Vehicles.Find(vehicleIndexViewModel.VehicleID);
    //To test for concurrency errors
    //vehicle.Timestamp = vehicleIndexViewModel.Timestamp;  

    db.Entry(vehicle).State = EntityState.Deleted;
    db.SaveChanges();
    return RedirectToAction("Index");
  }
  catch (DbUpdateConcurrencyException)
  {
    return RedirectToAction("Index", 
      new System.Web.Routing.RouteValueDictionary{{"concurrencyError", true }});
  }
  catch (DataException)
  {
    //Log the error (add a variable name after Exception)
    ModelState.AddModelError(string.Empty, "The system was unable to delete that" 
      + " vehicle. Try again, and if the problem persists"
      + " contact your system administrator.");
    return RedirectToAction("Index");
  }
}

Независимо от того, что пользователь должен быть перенаправлен на страницу указателя.Вот действие Get страницы индекса:

public ViewResult Index(bool? concurrencyError)
{
  if (concurrencyError.GetValueOrDefault())
  {
    ViewBag.ConcurrencyErrorMessage = "The record you attempted to delete "
      + "was modified by another user after you got the original values. "
      + "The delete operation was canceled and the current values in the "
      + "database have been displayed. If you still want to delete this "
      + "record, click the Delete button again. Otherwise "
      + "click the Back to List hyperlink.";
  }

  IEnumerable<Vehicle> vehicles = db.Vehicles.Include(v => v.VehicleType);

  IEnumerable<VehicleIndexViewModel> viewModel 
    = Mapper.Map<IEnumerable<Vehicle>, 
                 IEnumerable<VehicleIndexViewModel>>(vehicles);

  return View(viewModel);
}

Код никогда не перехватывает ошибку параллелизма.Я тестирую, открывая страницу индекса дважды.На одной из страниц я открываю страницу редактирования автомобиля и что-то меняю.После сохранения я возвращаюсь на другую страницу и нажимаю «Удалить». Действие Удалить запускается, и транспортное средство удаляется, но ошибка параллелизма не обнаруживается. Вы можете видеть, где я закомментировал vehicle.Timestamp = vehicleIndexViewModel.Timestamp ;.Я думал, что возвращение значения viewModel обратно в фактическое приведет к возникновению ошибки, но это тоже не сработает.

Я уверен, что есть что-то, чего я не понимаю, но что яделать неправильно?

EDIT

Эрик Филипс обнаружил логическую ошибку, которая у меня была, но была другая проблема, с которой я столкнулся сразу.Моя ViewModel не возвращала данные метки времени.Фактически, единственными данными, которые он возвращал, был VehicleID.

Когда я пытался добавить скрытое поле в форму, я получал ошибку.Код чуть ниже этого не будет работать:

<input type="hidden" name="Timestamp" value="@item"/>

Поле Timestamp должно быть допустимой строкой Base-64.Вы получите сообщение об ошибке:

Введенные данные не являются допустимой строкой Base-64, так как содержат не базовый 64-символ, более двух символов заполнения или не пробелсреди отступающих персонажей.

Вот так я и сохранил значение метки времени в представлении:

<input type="hidden" name="Timestamp" value="@Convert.ToBase64String(item.Timestamp)"/> 

Итак, весь мой Html.BeginForm выглядит так:

@using (Html.BeginForm("Delete", "Vehicle",  FormMethod.Post, null))
{                                        
    <input type="hidden" name="VehicleID" value="@item.VehicleID"/>  
    <input type="hidden" name="VehicleName" value="@item.VehicleName"/> 
    <input type="hidden" name="Timestamp" value="@Convert.ToBase64String(item.Timestamp)"/>                                
    <input type="image" src="../../Content/Images/Delete.gif" value="Delete" name="deletevehicle @item.VehicleID" onclick="return confirm('Are you sure you want to delete @item.VehicleName.Replace("'", "").Replace("\"", "")?');"/>  
}  

Хотя мне действительно не нужно было помещать VehicleName в скрытое поле.

Как только это было сделано, все, что мне нужно было сделать, это использовать AutoMapper, чтобы отобразить значения обратно в объект транспортного средства, установить EntityStateУдалить и попробуйте сохранить изменения;

try
{
    Vehicle vehicle = Mapper.Map<VehicleIndexViewModel, Vehicle>(vehicleIndexViewModel);
    db.Entry(vehicle).State = EntityState.Deleted;
    db.SaveChanges();
    return RedirectToAction("Index");
}
catch (DbUpdateConcurrencyException)
{
    return RedirectToAction("Index", new System.Web.Routing.RouteValueDictionary { { "concurrencyError", true } });
}

Вот и все!

1 Ответ

1 голос
/ 03 апреля 2012

Вот что я увидел бы, если бы эти события происходили в следующем порядке:

Пользователь 1

Vehicle / Edit VehicleID = 1 (Timestamp = =1)

Пользователь 2

Vehicle / Edit VehicleID = 1 (Timestamp = 1)

Пользователь 1

Vehicle / Update VehicleID = 1, Title = "Some Text", (Timestamp = 2)

User2

Vehicle / DeleteConfirmed VehicleID = 1, Timestamp = 1

/* DeleteConfirmed */

// Default Model Binder 
VehicleIndexViewModel.VehicleID = 1
VehicleIndexViewModel.Timestamp = 1

Vehicle vehicle = db.Vehicles.Find(vehicleIndexViewModel.VehicleID);
//vehicle.VehicleID = 1
//vehicle.Timestamp = 2

// Set to Delete
db.Entry(vehicle).State = EntityState.Deleted;

// Delete in database
db.SaveChanges();

По сути, все, что вы делаете, это извлекаете Автомобиль в его текущем состоянии (обновлено от пользователя 1) и удалив его.Если, по какой-то странной случайности, кто-то сделает обновление между Find и SaveChanges, то никогда не будет DbUpdateConcurrencyException.

Я полагаю, что вместо этого вы можете сделать Прикрепить объект в контекст, удалите его, затем вызовите SaveChanges().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...