none
Por que UpdateModel no actualiza correctamente la base de datos? RRS feed

  • Pregunta

  • Hola estoy usando LINQ to SQL  y estoy reproduciendo paso a paso el tutorial de NerdDinner, pero al momento de realizar la actualizacion de una Dinner(Comida :P :D) no se realiza correctamente, no entiendo por qué, a alguien le sucedio esto antes?

     

    Gracias!


    Coding "La lucha diaria" - D3S........D4S
    Necesitamos un voto:Aquí
    domingo, 19 de septiembre de 2010 17:22

Respuestas

  • Hola!

    A ver, debes usar este código:

        //POST: /Dinners/Edit/[id]
        [AcceptVerbs(HttpVerbs.Post), Authorize]
        public ActionResult Edit(int id, FormCollection form)
        {
    
          DinnerFormViewModel dvm = new DinnerFormViewModel(db.GetDinner(id));
          
          //Is valid User
          if (!dvm.Dinner.IsHostBy(User.Identity.Name))
            return View("InvalidOwner");
    
          try
          {
            UpdateModel(dvm, form.ToValueProvider());
            db.Save();
            return RedirectToAction("Details", new { id = dvm.Dinner.DinnerID });
          }
          catch(Exception EX)
          {
            ModelState.AddModelError("", EX.Message);
            ModelState.AddRuleViolations(dvm.Dinner.GetRuleViolations());
            return View(dvm);
          }
        }
    
    

    Ok... Y ahora la explicación! :D

    La vista DinnerForm.ascx trabaja con un Model cuyo tipo es DinnerFormViewModel. Cuando en DinnerForm haces:

    <%: Html.TextBoxFor(model => model.Dinner.Title) %>

    Esto genera un tag <input type="text" name="Dinner.Title" />

    Por lo tanto en el método del controlador, en FormsCollection tienes una entrada "Dinner.Title".

    Eso significa que UpdateModel() buscará una propiedad Title de otra propiedad Dinner, del objeto que se le pase. Pero tu estabas haciendo un UpdateModel() directamente del Dinner (que tiene la propiedad Title, pero no la Dinner.Title).

    Es por ello que debes pasar al UpdateModel un objeto... DinnerFormViewModel! :)

    DinnerFormViewModel si que tiene la propiedad Dinner, que dentro tiene la propiedad Title, así pues UpdateModel es capaz de hacer binding entre el campo Form de la Request "Dinner.Title" y la propiedad Title de la propiedad Dinner del DinnerFormViewModel pasado.

    En resumen: Si la vista trabaja con un ViewModel de un tipo, el controlador debe trabajar con el mismo ViewModel! (No vale user DinnerFormViewModel a la vista y Dinner en el controlador).

    Un saludo!

    pd: Por cierto, este ejemplo está bastante desactualizado (es MVC1)... estaría bien que pillases algún ejemplo más actualizado (MVC2) porque algunas de las cosas ya no se usan (sí... mvc avanza muy rápido :P).

    pd2: Otro saludo! 


    Eduard Tomàs Blog: http://geeks.ms/blogs/etomas -- Twitter: eiximenis
    • Marcado como respuesta Felipe Sotelo S lunes, 20 de septiembre de 2010 16:17
    lunes, 20 de septiembre de 2010 16:06

Todas las respuestas

  • Buenas Felipe,

    Pues no se que decirte... Te da error? Simplemente no te actualiza nada? Que código usas?

    Posibles puntos de fallo:

    1. Que llames a UpdateModel, pero luego te olvides de llamar al método del contexto de Linq2Sql para persistir los cambios en BBDD (que te dejes el SubmitChanges).
    2. Que tengas algún campo que no debas actualizar pero esté presente en los datos enviados al controlador. En este caso deberías indicarle a UpdateModel que no actualizara esos datos (si no al estar presentes en los datos enviados UpdateModel intentará actualizarlos).

    Echale un vistazo a esta discusió en stackoverflow donde cuentan eso mismo pero con más detalle: http://stackoverflow.com/questions/1069197/asp-net-mvc-linq-and-updatemodel-issues

    Un saludo!

     


    Eduard Tomàs Blog: http://geeks.ms/blogs/etomas -- Twitter: eiximenis
    lunes, 20 de septiembre de 2010 6:28
  • Hola el codigo es el siguiente:

     

     

    //POST: /Dinners/Edit/[id]

    [

     

    AcceptVerbs(HttpVerbs.Post), Authorize]

     

     

    public ActionResult Edit(int id, FormCollection form)

    {

     

     

    Dinner dinner = db.GetDinner(id);

     

     

    //Is valid User

     

     

    if (!dinner.IsHostBy(User.Identity.Name))

     

     

    return View("InvalidOwner");

     

     

    try

    {

    UpdateModel(dinner, form.ToValueProvider());

    db.Save();

     

     

    return RedirectToAction("Details", new { id = dinner.DinnerID });

    }

     

     

    catch(Exception EX)

    {

    ModelState.AddModelError(

     

    "", EX.Message);

    ModelState.AddRuleViolations(dinner.GetRuleViolations());

     

     

    return View(new DinnerFormViewModel(dinner));

    }

    }

     

    No entra a ninguna excepción ni nada simplemente no funciona, hace el save pero los cambios no se ven reflejados. Saludos, gracias y quedo atento a las sugerencias


    Coding "La lucha diaria" - D3S........D4S
    Necesitamos un voto:Aquí
    lunes, 20 de septiembre de 2010 14:30
  • Hola Felipe,

    Perdon por meterme por medio del tema,

     

    Podrias probar asi:

     

    [AcceptVerbs(HttpVerbs.Post), Authorize]
    
    public ActionResult Edit(int id, FormCollection form)
    
    {
    
     
    
    Dinner dinner = db.GetDinner(id);
    
     
    
    //Is valid User
     
    
    if (!dinner.IsHostBy(User.Identity.Name))
    
     return View("InvalidOwner");
    
     
    try
    
    {
    
    UpdateModel(dinner);
    
    db.Save();
    
    return RedirectToAction("Details", new { id = dinner.DinnerID });
    
    }
    
     catch(Exception EX)
    
    {
    
    ModelState.AddModelError("", EX.Message);
    
    ModelState.AddRuleViolations(dinner.GetRuleViolations());
    
    return View(new DinnerFormViewModel(dinner));
    
    }
    
    }
    


    Para el correcto funcionamiento, y que otros usuarios se puedan beneficiar de la solucion de esta pregunta por favor marca las respuestas que te hayan ayudado como "Respuesta".
    Si la respuesta te ha sido util Votala.
    Mi Blog: Jtorrecilla
    Enlace a Faq de Winforms en Ingles Muy bueno
    lunes, 20 de septiembre de 2010 14:35
  • Hola muchas gracias por responder, pero ya intente así antes!!!! lo que mas me impresiona es que en que parte se asocia el FormCollection!!!????

    De todas formas no funciana :(..... gracias!!!


    Coding "La lucha diaria" - D3S........D4S
    Necesitamos un voto:Aquí
    lunes, 20 de septiembre de 2010 14:37
  • Hace el save y te redirige a la página de Detalles?
    Para el correcto funcionamiento, y que otros usuarios se puedan beneficiar de la solucion de esta pregunta por favor marca las respuestas que te hayan ayudado como "Respuesta".
    Si la respuesta te ha sido util Votala.
    Mi Blog: Jtorrecilla
    Enlace a Faq de Winforms en Ingles Muy bueno
    lunes, 20 de septiembre de 2010 14:40
  • sip!!! sin ningun error
    Coding "La lucha diaria" - D3S........D4S
    Necesitamos un voto:Aquí
    lunes, 20 de septiembre de 2010 14:43
  • Podrias poner el código de la vista?


    Para el correcto funcionamiento, y que otros usuarios se puedan beneficiar de la solucion de esta pregunta por favor marca las respuestas que te hayan ayudado como "Respuesta".
    Si la respuesta te ha sido util Votala.
    Mi Blog: Jtorrecilla
    Enlace a Faq de Winforms en Ingles Muy bueno
    lunes, 20 de septiembre de 2010 14:44
  • Ok si pero depurando, luego de que hace el save, quiero ver si el modelo se actualizo, es decir le doy Vista Rápida y los items de dinner permanecen tal cual sin ninguna modificación.... agrego el partial view del formDinner que se usa para la vista de creación y la de edición....

    <%

     

    @ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<NerdDinnerOK.Models.DinnerFormViewModel>" %>

    <

     

     

    asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">

    Editar Comida

    </

     

     

    asp:Content>

    <

     

     

    asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

     

     

    <h2>Editar Comida: <%=Html.Encode(Model.Dinner.Title) %></h2>

    <% Html.RenderPartial(

     

    "DinnerForm"); %>

     

     

     

    <div>

    <%

     

    : Html.ActionLink("Regresar", "Details", new { id = Model.Dinner.DinnerID })%>

     

     

    </div>

    </

     

     

    asp:Content>

    <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserCoYntrol<NerdDinnerOK.Models.DinnerFormViewModel>" %>
    
     <%= Html.ValidationSummary("Por favor corrija los error antes de enviar los datos") %>
      <% using (Html.BeginForm()) {%>
        
        
        <fieldset>
        <legend>Caracteristicas </legend>
        <table width="100%"><tr ><td style="width:20%">
          <div class="editor-label">
            <%: Html.Label("Título") %>
          </div>
          <div class="editor-field">
            <%: Html.TextBoxFor(model => model.Dinner.Title) %>
            <%: Html.ValidationMessageFor(model => model.Dinner.Title, "*") %>
          </div>
          
          <div class="editor-label">
            <%: Html.Label("Día Evento") %>
          </div>
          <div class="editor-field">
            <%: Html.TextBoxFor(model => model.Dinner.EventDay, String.Format("{0}", Model.Dinner.EventDay.ToShortDateString()))%>
            <%: Html.ValidationMessageFor(model => model.Dinner.EventDay, "*") %>
          </div>
          
          <div class="editor-label">
            <%: Html.Label("Descripción") %>
          </div>
          <div class="editor-field" style="Height:90px">
            <%: Html.TextAreaFor(model => model.Dinner.Description, new {rows = "4", cols = "23" })%>
            <%: Html.ValidationMessageFor(model => model.Dinner.Description, "*") %>
          </div>
          <div class="editor-label">
            <%: Html.Label("Teléfono Contacto") %>
          </div>
          <div class="editor-field">
            <%: Html.TextBoxFor(model => model.Dinner.ContactPhone) %>
            <%: Html.ValidationMessageFor(model => model.Dinner.ContactPhone, "*") %>
          </div>
          
          <div class="editor-label">
            <%: Html.Label("Dirección") %>
          </div>
          <div class="editor-field">
            <%: Html.TextBoxFor(model => model.Dinner.Address) %>
            <%: Html.ValidationMessageFor(model => model.Dinner.Address, "*") %>
          </div>
          
          <div class="editor-label">
            <%: Html.Label("País") %>
          </div>
          <div class="editor-field">
            <%: Html.DropDownListFor(model=>Model.Dinner.Country, Model.Countries) %>
            <%: Html.ValidationMessageFor(model => model.Dinner.Country, "*") %>
          </div>
          
          <div class="editor-label">
            <%: Html.Label("Latitud") %>
          </div>
          <div class="editor-field">
            <%: Html.TextBoxFor(model => model.Dinner.Latitude, String.Format("{0:F}", Model.Dinner.Latitude)) %>
            <%: Html.ValidationMessageFor(model => model.Dinner.Latitude, "*") %>
          </div>
          
          <div class="editor-label">
            <%: Html.Label("Longitud") %>
          </div>
          <div class="editor-field">
            <%: Html.TextBoxFor(model => model.Dinner.Longitude, String.Format("{0:F}", Model.Dinner.Longitude)) %>
            <%: Html.ValidationMessageFor(model => model.Dinner.Longitude, "*") %>
          </div>
          
          <p>
            <input type="submit" value="Save" />
          </p>
         </td><td style="position:absolute;width:auto;height:auto;">
          
          <% Html.RenderPartial("Map", Model.Dinner); %>
          </td></tr></table> 
    
    
        </fieldset>
        <script type="text/javascript">
    
          $(document).ready(function () {
            $("#Address").blur(function (evt) {
              $("#Latitude").val("");
              $("#Longitude").val("");
              var address = jQuery.trim($("#Address").val());
              if (address.length < 1)
                return;
              FindAddressOnMap(address);
            });
          });
        </script>
      <% } %>
    
      
    lunes, 20 de septiembre de 2010 14:48
  • Me refiero a la Vista de Edición, no de detalle.
    Para el correcto funcionamiento, y que otros usuarios se puedan beneficiar de la solucion de esta pregunta por favor marca las respuestas que te hayan ayudado como "Respuesta".
    Si la respuesta te ha sido util Votala.
    Mi Blog: Jtorrecilla
    Enlace a Faq de Winforms en Ingles Muy bueno
    lunes, 20 de septiembre de 2010 14:52
  • Hola, ya actualice el post
    Coding "La lucha diaria" - D3S........D4S
    Necesitamos un voto:Aquí
    lunes, 20 de septiembre de 2010 14:55
  • A simplemente la veo correcta.

     

     

    Mira yo hice hace un tiempo este ejemplo en VB, te pongo el código para que lo veas, y te digo que a mi me funciona tal cual.

     

     

    <AcceptVerbs(HttpVerbs.Post)> _
        Public Function Edit(ByVal id As Integer, ByVal formValues As FormCollection) As ActionResult
    
          Dim dinn As Dinner = dinnersRepository.GetDinner(id)
          Try
          UpdateModel(dinn)
            dinnersRepository.Save()
            Return RedirectToAction("Details", New With {.id = dinn.DinnerID}) 'DUDA
          Catch ex As Exception
    
            For Each str As RuleViolation In dinn.GetRuleViolations()
              ModelState.AddModelError(str.PropertyName, str.ErrorMessage)
            Next
    
          End Try
          Return View(dinn)
        End Function
    El método UpdateModel es capaza de rescatar los valores del formulario para llevar a cabo la modificación.
    Para el correcto funcionamiento, y que otros usuarios se puedan beneficiar de la solucion de esta pregunta por favor marca las respuestas que te hayan ayudado como "Respuesta".
    Si la respuesta te ha sido util Votala.
    Mi Blog: Jtorrecilla
    Enlace a Faq de Winforms en Ingles Muy bueno
    lunes, 20 de septiembre de 2010 14:59
  • "El método UpdateModel es capaza de rescatar los valores del formulario para llevar a cabo la modificación. "
    Pues no es tan capaz!!!!! por que no lo hace.  Qué podría ser?
    Coding "La lucha diaria" - D3S........D4S
    Necesitamos un voto:Aquí
    lunes, 20 de septiembre de 2010 15:01
  • Te animas a subir tu ejemplo a SkyDrive, y le doy un vistazo?
    Para el correcto funcionamiento, y que otros usuarios se puedan beneficiar de la solucion de esta pregunta por favor marca las respuestas que te hayan ayudado como "Respuesta".
    Si la respuesta te ha sido util Votala.
    Mi Blog: Jtorrecilla
    Enlace a Faq de Winforms en Ingles Muy bueno
    lunes, 20 de septiembre de 2010 15:03
  • http://cid-0f95789c4f3186d7.office.live.com/browse.aspx/.Public Aquí va...Gracias ;)
    Coding "La lucha diaria" - D3S........D4S
    Necesitamos un voto:Aquí
    lunes, 20 de septiembre de 2010 15:17
  • Hola!

    A ver, debes usar este código:

        //POST: /Dinners/Edit/[id]
        [AcceptVerbs(HttpVerbs.Post), Authorize]
        public ActionResult Edit(int id, FormCollection form)
        {
    
          DinnerFormViewModel dvm = new DinnerFormViewModel(db.GetDinner(id));
          
          //Is valid User
          if (!dvm.Dinner.IsHostBy(User.Identity.Name))
            return View("InvalidOwner");
    
          try
          {
            UpdateModel(dvm, form.ToValueProvider());
            db.Save();
            return RedirectToAction("Details", new { id = dvm.Dinner.DinnerID });
          }
          catch(Exception EX)
          {
            ModelState.AddModelError("", EX.Message);
            ModelState.AddRuleViolations(dvm.Dinner.GetRuleViolations());
            return View(dvm);
          }
        }
    
    

    Ok... Y ahora la explicación! :D

    La vista DinnerForm.ascx trabaja con un Model cuyo tipo es DinnerFormViewModel. Cuando en DinnerForm haces:

    <%: Html.TextBoxFor(model => model.Dinner.Title) %>

    Esto genera un tag <input type="text" name="Dinner.Title" />

    Por lo tanto en el método del controlador, en FormsCollection tienes una entrada "Dinner.Title".

    Eso significa que UpdateModel() buscará una propiedad Title de otra propiedad Dinner, del objeto que se le pase. Pero tu estabas haciendo un UpdateModel() directamente del Dinner (que tiene la propiedad Title, pero no la Dinner.Title).

    Es por ello que debes pasar al UpdateModel un objeto... DinnerFormViewModel! :)

    DinnerFormViewModel si que tiene la propiedad Dinner, que dentro tiene la propiedad Title, así pues UpdateModel es capaz de hacer binding entre el campo Form de la Request "Dinner.Title" y la propiedad Title de la propiedad Dinner del DinnerFormViewModel pasado.

    En resumen: Si la vista trabaja con un ViewModel de un tipo, el controlador debe trabajar con el mismo ViewModel! (No vale user DinnerFormViewModel a la vista y Dinner en el controlador).

    Un saludo!

    pd: Por cierto, este ejemplo está bastante desactualizado (es MVC1)... estaría bien que pillases algún ejemplo más actualizado (MVC2) porque algunas de las cosas ya no se usan (sí... mvc avanza muy rápido :P).

    pd2: Otro saludo! 


    Eduard Tomàs Blog: http://geeks.ms/blogs/etomas -- Twitter: eiximenis
    • Marcado como respuesta Felipe Sotelo S lunes, 20 de septiembre de 2010 16:17
    lunes, 20 de septiembre de 2010 16:06
  • Sip vamos ya en MVC 3 :P :D.......de eso me estoy dando cuenta!!!!! un saludo, gracias por la respuesta le veo mucho sentido!!!! voya probar ya te cuento!!!

    MVC 3.0 :P

    http://weblogs.asp.net/scottgu/archive/2010/07/27/introducing-asp-net-mvc-3-preview-1.aspx


    Coding "La lucha diaria" - D3S........D4S
    Necesitamos un voto:Aquí
    lunes, 20 de septiembre de 2010 16:10
  • Si señor!!!!!! que inteligente muchas gracias !!!!!
    Coding "La lucha diaria" - D3S........D4S
    Necesitamos un voto:Aquí
    lunes, 20 de septiembre de 2010 16:17