Странное поведение в ASP.NET MVC: удаление элемента из списка во вложенной структуре всегда удаляет последний элемент - PullRequest
2 голосов
/ 14 декабря 2010

Сценарий

У меня есть модель родителя / ребенка (точнее, небольшая анкета и одно или несколько контактов).По историческим причинам все это было бы сделано в одной и той же форме, поэтому у пользователя была бы форма для родителя и одного ребенка, и они нажимали кнопку, чтобы добавить больше детей.У ребенка есть несколько стандартных полей и то же самое с родителем, ничего особенного.Основное требование заключается в том, что данные не должны касаться базы данных, пока все не станет действительным и не настроено, а мне придется вернуться на сервер для добавления удаляющих потомков.

Реализация

Это было очень быстро, чтобы заставить это работать в ASP.NET MVC (используя MVC 2 с VS 2010 ).Я получил две модели, одну для родителей и одну для ребенка, и получил только один контроллер.Контроллер имеет метод Create, который является get и получает представление по умолчанию со свежим новым родителем, содержащим одного дочернего элемента.Я использую шаблон редактора для дочерней модели, которая работает хорошо.

У меня есть одна HTML-форма, в которой есть "сохранить" и "добавить дочерний элемент", и у меня есть кнопка "удалить" для каждой формы,Так как это не может быть сохранено в базе данных, я храню временную модель в самой форме, и она перемещается между браузером и сервером.Производительность здесь не так важна, как стоимость разработки, поскольку таких форм довольно много, поэтому, пожалуйста, не отвлекайтесь слишком сильно, предлагая альтернативный подход, хотя я все равно ценю комментарии.

чтобы выяснить, какой дочерний элемент удаляется, я создаю временные идентификаторы GUID и связываю их с дочерним элементом.Это перейдет к значению ввода HTML для кнопки удаления (обычный прием, когда у вас есть несколько действий и одна и та же форма).

Я отключил кэширование.

Issue

Пожалуйста, посмотрите на фрагменты ниже.Я отладил код, и я всегда видел, как передается правильный GUID, правильный элемент удаляется из списка в контроллере и корректные элементы отображаются в шаблоне.Но всегда последний удаляется !!Я обычно нажимаю на первое удаление и вижу, что последнее удаляется.Я продолжаю, и первый элемент является последним удаляемым.

Контроллер

    public ActionResult Create()
    {
        EntryForm1 entryForm1 = new EntryForm1();
        entryForm1.Children.Add(new Child("FILL ME", "FILL ME"){ TempId = Guid.NewGuid()});
        return View("EntryForm1View", entryForm1);
    }

    [HttpPost]
    public ActionResult Create(EntryForm1 form1, FormCollection collection, string add)
    {
        if (add == "add")
            form1.Children.Add(new Child("FILL ME", "FILL ME") {TempId = Guid.NewGuid()});

        var deletes = collection.AllKeys.Where(s => s.StartsWith("delete_"));
        collection.Clear();
        if (deletes.Count() > 0)
        {
            string delete = deletes.FirstOrDefault();
            delete = delete.Replace("delete_", "");
            Guid g = Guid.Parse(delete);
            var Children = form1.Children.Where(x => x.TempId == g).ToArray();
            foreach (Child child in Children)
            {
                form1.Children.Remove(child);
            }               
            // HERE CORRECT ITEM IS DELETED, BELIEVE ME!!
        }
        if (ModelState.IsValid)
        {
            return Redirect("/");
        }
        return View("EntryForm1View", form1);
    }

Просмотреть фрагмент

    <% for (int i = 0; i < Model.Children.Count;i++ )
  {%>
        <h4> <%: Html.EditorFor(m=>m.Children[i])%></h4>

        <%
  }%>
        <p>
            <input type="submit" value="Create" name="add" />
            <input type="submit" value="add" name="add" />
        </p>

Фрагмент шаблона дочернего редактора

        <%: Html.HiddenFor(x=>x.TempId) %>
        </span>
        <input type="submit" name='delete_<%: Html.DisplayTextFor(m => m.TempId) %>' value="Delete" />

Большое спасибо за ваше время и внимание


ОБНОВЛЕНИЕ

Меня спросили о модельных классах, и я делюсь ими так же, как и они.Entryform1 является родителем , а Somesing является дочерним .

открытым классом Somesing {

    public Somesing()
    {

    }

    public Somesing(string o, string a) : this()
    {
        OneSing = o;
        AnozerSing = a;
    }

    [StringLength(2)]
    public string OneSing { get; set; }

    [StringLength(2)]
    public string AnozerSing { get; set; }

    public Guid TempId { get; set; }

}

public class EntryForm1
{

    public EntryForm1()
    {
        Sings = new List<Somesing>();
    }

    public string FirstName { get; set; }

    public string LastName { get; set; }

    public int Age { get; set; }

    public List<Somesing> Sings { get; set; }

}

Ответы [ 3 ]

7 голосов
/ 15 декабря 2010

Я считаю, что проблема заключается в ModelState. Когда представление отображается, что, как я полагаю, лежит в основе проблемы, после POST, последнее значение не отображается, т.е. удаляется из представления.

Проблема в том, что Model.Children.Count вернет правильное количество элементов для отображения.

Давайте разберемся с этим ...

Итак, если у вас изначально было 5, а затем удалили первое, которое имеет индекс 0 на основе Guid, теперь у вас осталось 4 элемента с индексами от 1 до 4.

Однако при рендеринге представления после публикации HtmlHelpers смотрит не на значения в опубликованной модели, а на значения, содержащиеся в ModelState. Таким образом, в ModelState элемент с индексом 0 по-прежнему существует, и поскольку цикл теперь повторяется до 4, последний элемент не будет отображаться.

Решение, используйте ModelState.Clear()

2 голосов
/ 20 октября 2015

ModelState.Clear () решит эту проблему.

ModelState.Clear () используется для очистки ошибок, но также используется для принудительной MVCдвигатель для восстановления модели, которая будет передана в ваш вид.

1 голос
/ 18 декабря 2010

ОК, как отметил Ахмад, ModelState является ключом к проблеме.Он содержит коллекцию как таковую:

  • FirstName
  • LastName
  • ...
  • Поет [0] .OneSing
  • Поет [0]. AnozerSing
  • поет [1] .OneSing
  • поет [1] .AnozerSing
  • поет [2] .OneSing
  • поет[2] .AnozerSing

Теперь, если я удаляю элемент 0 из списка, теперь элементы будут перемещаться вверх по списку, и данные в ModelState будут не синхронизированы с моделью.Я ожидал, что ASP.NET MVC будет достаточно умным, чтобы выяснить и изменить порядок, но это требует слишком многого.

Я фактически реализовал PRG (post-redirect-get) и сохранил модельво время сеанса я смог отобразить правильную информацию, но снова, это удалит все проверки в коллекции, и если сама модель действительна, она с радостью сохранит и перенаправит обратно на дом "/". Очевидно, этонеприемлемо.

Итак, Одно из решений - удалить все элементы в ModelState и затем добавить новую запись для самой модели (с ключом EmptyString).Это может действительно работать нормально, если вы заполняете его с ошибкой «Элемент удален», так как это будет отображаться в сводке проверки.

Другое решение - это вручную изменить элементы в состоянии модели ипереставить их на основе новых индексов.Это не легко, но возможно.

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