2011-03-25 6 views
11

Tengo 1 cuadro de texto usando TextBoxFor que contiene los datos.El modelo Razor MVC está perdiendo datos en la acción Guardar

Tengo un id para el modelo y algunos otros datos básicos pero se muestran como etiquetas directamente en la vista.

Cuando envío el formulario, solo el campo de la caja de texto tiene datos sobre el modelo, todo lo demás es nulo, incluido el Id. Esto significa que no guardará en la base de datos.

¿Qué causa que todos los campos sean nulos aparte del cuadro de texto?

+0

Publicar por favor su código .. –

+1

Publique el código * minimal * (es decir, no toda la aplicación) que ilustra el problema. Incluya su código de vista así como los métodos de acción relevantes. – marcind

+0

@Bugai, sé que es difícil diagnosticar el problema sin código, pero es realmente bastante difícil publicar código cuando tienes grandes piezas de código en 1) la vista, 2) el controlador, 3) el modelo y todos estos contienen contexto que es irrelevante para el problema. – jaffa

Respuesta

16

Esta es la forma en que funciona web, sólo se forman elementos son enviadas con la forma y las etiquetas no se forman elementos.

Lo que comúnmente ocurre aquí es que:

  1. hacer Un campo oculto (Html.Hidden/Html.HiddenFor) que contiene la identificación junto con los cuadros de texto
  2. aceptar los cambios en su acción del controlador (como parámetros o una objeto)
  3. hidratar la instancia del objeto representada por ID de su repositorio/base de datos
  4. aplicar los cambios a la instancia hidratado
  5. Validar el estado del objeto y actualizar su repositorio/base de datos (o lo que estábamos planeando hacer con ella)

A medida que la clase de datos publicado es a menudo "no válido", debido a sus propiedades faltantes (los marcados como [Required] por ejemplo), es muy común crear una nueva clase que solo tenga las propiedades cambiadas (llamado "modelo de comando"). Esta clase puede tener sus propias propiedades de validación y, por lo tanto, no ensuciar con la validación de su formulario.

+0

Excelente, gracias por la respuesta clara y concisa. Esto lo hace mucho más claro, ¡hay un poco de trabajo por hacer de mi parte para eliminar la mentalidad de forma de red de mi cerebro! – jaffa

6

Solo las entradas se vuelven a enviar al servidor. Si desea que el modelo se rellene en función de los datos de la página, debe estar en entradas (o parte de la URL). Los datos en los elementos de la etiqueta no se publicarán en el servidor con el formulario (este es el comportamiento de formulario HTML estándar). Por lo general, debe utilizar los campos ocultos para publicar datos de modelos no editables o simplemente hacer referencia al ID del modelo y volver a llenar la base de datos, actualizando las propiedades editables (como se muestra a continuación).

Ejemplo:

@(using Html.BeginForm(new { id = Model.ID })) 
{ 
     <p> 
      <label>Fixed Property:</label> 
      @Model.SomeFixedProperty 
     </p> 
     <p> 
      @Html.LabelFor(m => m.EditableProperty) 
      @Html.TextBoxFor(m => m.EditableProperty) 
     </p> 
} 

Controller

[HttpPost] 
public ActionResult Foo(int id, string editableProperty) 
{ 
    var model = repo.GetById(id); 
    model.EditableProperty = editableProperty; 
    repo.Save(); 
    return View(model); 
} 
+0

Bien, pero qué pasa si tiene un formulario completo que muestra 10 etiquetas y 1 etiqueta para editar. ¿Cómo se supone que debo devolver estos datos al modelo sin que se haya restablecido todo? Parece que este es un problema importante que ViewState habría resuelto? – jaffa

+1

@Jon - (1) campos ocultos para ir junto con la etiqueta de cada cosa que necesita volver a llenar en el modelo, (2) usar TempData para contener datos de la solicitud anterior, o (3) incluir suficiente información para reformular los datos necesarios . ViewState realmente funciona (1), aunque los datos están encriptados. Si así lo desea, podría replicar esta funcionalidad, pero yo no lo recomendaría. Por lo que dices, probablemente elegiría (3) e incluiría el ID del modelo en la url. Haga que su acción de controlador tome la identificación y los datos actualizados como parámetros. Recupere el modelo de la base de datos y modifíquelo solo cuando sea necesario. – tvanfosson

+0

@Jon - Consulte el estado de la sesión y comprenda cómo se escala antes de confiar en 'TempData', ya que eso es lo que' TempData' envuelve. –

0

Aunque estoy de acuerdo con @RichardSzalay, otra forma sería marcar las propiedades sin modificar como no modificadas.

Supongamos que tiene un modelo con estas propiedades: Id, Nombre, Correo electrónico. Y no quiere cambiar el correo electrónico.

public ActionResult ChangeName([Bind(Include="Id,Name")] User model) 
{ 
    // ... 
    db.Entry(model).State = EntityState.Modified; 
    db.Entry(model).Property(m => m.Email).IsModified = false; 
    db.SaveChanges(); 
    // ... 
} 

El inconveniente es que puede tener problemas de validación debido a que faltan campos en el modelo.

Cuestiones relacionadas