Модели самоконтроля MVC 2 и EF4 имеют плохое состояние при обратной передаче - PullRequest
1 голос
/ 24 сентября 2010

У меня есть стандартные методы Create () Edit () и Delete () на моих контроллерах, и я использую объекты EF4 Self-tracking.

Когда редактирование отправляется обратно, model.ChangeTracker.ChangeTracking = false и model.ChangeTracker.State = ObjectState.Added, хотя я убедился, что они установлены при первоначальном получении записи.

Не отслеживают ли самопроверяемые объекты класс ChangeTracker при отправке формы? Если так, как я могу это исправить?

public virtual ActionResult Edit(int personId)
{
    IContext context = ContextFactory.GetContext();
    EntityRepo Repo = new EntityRepo(context);
    Person d = Repo.Person.GetById(PersonId);
    d.ChangeTracker.ChangeTrackingEnabled = true;
    return View(d);
}

[HttpPost]
public virtual ActionResult Edit(int personId, Person item)
{
    try
    {
        if (ModelState.IsValid)
        {
            IContext context = ContextFactory.GetContext();
            EntityRepo Repo = new EntityRepo(context);

            // the item is returning these properties that are wrong
            //item.ChangeTracker.ChangeTrackingEnabled = false;
            //item.ChangeTracker.State = ObjectState.Added;

            Repo.Person.Update(item);
            Repo.Person.SaveChanges();

            return RedirectToAction("Index");
        }
    }
    catch
    {
    }
    return View();
}

Ответы [ 5 ]

8 голосов
/ 27 сентября 2010

Давайте начнем с самого начала.

Что такое самообследуемые объекты?

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

Так когда же я действительно захочу?

Главным образом, когда у вас должны быть распределенные объекты.Например, один вариант использования - это когда вы создаете веб-сервис, который общается с клиентом Silverlight.Тем не менее, другие инструменты, такие как RIA Services, могут подойти лучше.Другой возможный вариант использования - для длительной задачи.Поскольку ObjectContext предназначен для использования в качестве единицы работы и, как правило, не должен быть долгоживущим, здесь может иметь смысл наличие отключенной сущности.

Имеют ли они какой-либо смысл для MVC?

Не совсем, нет.

Давайте посмотрим на это немного глубже и рассмотрим, что происходит, когда вы обновляете сущность в MVC.Общий процесс выглядит следующим образом:

  1. Браузер выдает запрос GET для страницы обновления.
  2. Приложение MVC извлекает объект и использует его для создания страницы HTML обновления.Страница подается в браузер, и большинство объектов C #, включая вашу сущность, удаляются.На этом этапе вы можете перезапустить веб-сервер, и браузер никогда не узнает разницу.
  3. Браузер выдает запрос POST для обновления сущности.
  4. Каркас MVC использует данные вPOST для материализации экземпляра модели редактирования, который передается действию обновления.Может случиться, что это тот же тип, что и у сущности, но это новый экземпляр.
  5. Приложение MVC может обновить сущность и передать эти изменения обратно в базу данных.

Теперь вы можете заставить самосопровождающие сущности работать, включив полное состояние STE в HTML-форму и отправив его обратно в приложение MVC вместе со скалярными значениями сущности.Тогда Самопроверкаемый субъект может, по крайней мере, работать.

Но что это даст вам?Браузер явно не может иметь дело с вашей сущностью как объектом C #.Таким образом, он не может вносить какие-либо изменения в сущность, которую стоит отслеживать, в терминах, понятных самопровозглашенной сущности.

2 голосов
/ 26 сентября 2010

U должен хранить оригинальный STE в каком-то скрытом поле. Это как ваш пользовательский ViewState. В методе отправки вы должны объединить оригинальный STE и новые значения.

Используйте для него ActionFilterAttribute.

Как

    public class SerializeOriginalModelAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        var viewResult = filterContext.Result as ViewResult;

        if (viewResult == null)
            return;

        var viewModel = viewResult.ViewData.Model as ViewModel;

        if (viewModel == null || viewModel.SteObject == null)
            return;

        byte[] bytes;
        using (var stream = new MemoryStream())
        {
            var serializer = new DataContractSerializer(viewModel.SteObject.GetType());
            serializer.WriteObject(stream, viewModel.SteObject);
            bytes = stream.ToArray();
        }

        var compressed = GZipHelper.Compress(bytes);
        viewModel.SerializedSteObject = Convert.ToBase64String(compressed);
    }
}





        public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext.ActionParameters == null || filterContext.ActionParameters.Count == 0)
            return;

        var viewModel  = filterContext.ActionParameters.First().Value as ViewModel;
        var serialized = filterContext.HttpContext.Request.Form["SerializedSteObject"];

        if (viewModel == null || String.IsNullOrEmpty(serialized))
            return;

        var type = filterContext.ActionParameters.First().Value.GetType().BaseType.GetGenericArguments()[0];

        var bytes = GZipHelper.Decompress(Convert.FromBase64String(serialized));
        using (var stream = new MemoryStream(bytes))
        {
            var serializer = new DataContractSerializer(type);
            viewModel.SteObject = serializer.ReadObject(stream);
        }
    }
}
1 голос
/ 03 октября 2010

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

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

И да, если вам нужно сохранить ваши STE между запросами, используйте сессию или представление.

1 голос
/ 24 сентября 2010

STE имеет один очень большой недостаток. Вы должны хранить их в состоянии сеанса или просмотра (WebForms). Так что это не что иное, как «новая версия набора данных». Если вы не храните STE, у вас будет один экземпляр для получения данных и другой для публикации = без отслеживания изменений.

0 голосов
/ 16 ноября 2010

Это должно быть

Repo.Person.ApplyChanges(item);  
Repo.Person.SaveChanges();

вместо

Repo.Person.Update(item);   
Repo.Person.SaveChanges();

Самотрекинг работает с методом расширения ApplyChanges.

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