Tutorial: Implementar la funcionalidad CRUD con Entity Framework en ASP.NET MVC

En el tutorial anterior, creó una aplicación MVC que almacena y muestra los datos con Entity Framework (EF) 6 y SQL Server LocalDB. En este tutorial, podrá revisar y personalizar el código CRUD (crear, leer, actualizar y eliminar) que el scaffolding de MVC crea automáticamente para usted en controladores y vistas.

Nota:

Es una práctica habitual implementar el modelo de repositorio con el fin de crear una capa de abstracción entre el controlador y la capa de acceso a datos. Para que estos tutoriales sean sencillos y se centren en enseñar a usar EF 6, no se usan repositorios. Para obtener información sobre cómo implementar repositorios, consulte el Mapa de contenido de acceso a datos de ASP.NET.

Estos son ejemplos de las páginas web que crea:

Recorte de pantalla de la página de detalles del alumno.

Recorte de pantalla de la página de creación de alumnos.

Recorte de pantalla de la página de eliminación de alumnos.

En este tutorial ha:

  • Creará una página de detalles
  • Actualizar la página Create
  • Actualizará el método HttpPost Edit
  • Actualizar la página Delete
  • Cerrar conexiones de bases de datos
  • Controlar transacciones

Requisitos previos

Crear una página de detalles

En el código con scaffolding de la página de Index de Students se excluyó la propiedad Enrollments porque contiene una colección. En la página Details, se mostrará el contenido de la colección en una tabla HTML.

En Controllers/StudentController.cs, el método de acción para la vista Details usa el método Find para recuperar una única entidad Student.

public ActionResult Details(int? id)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    Student student = db.Students.Find(id);
    if (student == null)
    {
        return HttpNotFound();
    }
    return View(student);
}

El valor de clave se pasa al método como parámetro id y procede de los datos de ruta del hipervínculo de detalles en la página de índice.

Sugerencia: Datos de ruta

Los datos de ruta son datos que el enlazador de modelos encontró en un segmento de dirección URL especificado en la tabla de enrutamiento. Por ejemplo, la ruta predeterminada especifica los segmentos de controller, action e id:

routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

En la dirección URL siguiente, la ruta predeterminada asigna Instructor como el controller, Index como la action y 1 como el id; estos son los valores de datos de ruta.

http://localhost:1230/Instructor/Index/1?courseID=2021

?courseID=2021 es un valor de cadena de consulta. El enlazador de modelos también funcionará si pasa el id como valor de cadena de consulta:

http://localhost:1230/Instructor/Index?id=1&CourseID=2021

Las instrucciones ActionLink crean las direcciones URL en la vista de Razor. En el siguiente código, el parámetro id coincide con la ruta predeterminada, por lo que se agrega id a los datos de la ruta.

@Html.ActionLink("Select", "Index", new { id = item.PersonID  })

En el siguiente código, courseID, no coincide con ningún parámetro de la ruta predeterminada, por lo que se agrega como una cadena de consulta.

@Html.ActionLink("Select", "Index", new { courseID = item.CourseID })

Para crear la página de detalles

  1. Abra Views/Students/Details.cshtml.

    Cada campo se muestra mediante un asistente DisplayFor, como se muestra en el ejemplo siguiente:

    <dt>
        @Html.DisplayNameFor(model => model.LastName)
    </dt>
    <dd>
        @Html.DisplayFor(model => model.LastName)
    </dd>
    
  2. Después del campo EnrollmentDate e inmediatamente antes de la etiqueta </dl> de cierre, agregue el código resaltado para mostrar una lista de inscripciones, como se muestra en el ejemplo siguiente:

    <dt>
                @Html.DisplayNameFor(model => model.EnrollmentDate)
            </dt>
    
            <dd>
                @Html.DisplayFor(model => model.EnrollmentDate)
            </dd>
            <dt>
                @Html.DisplayNameFor(model => model.Enrollments)
            </dt>
            <dd>
                <table class="table">
                    <tr>
                        <th>Course Title</th>
                        <th>Grade</th>
                    </tr>
                    @foreach (var item in Model.Enrollments)
                    {
                        <tr>
                            <td>
                                @Html.DisplayFor(modelItem => item.Course.Title)
                            </td>
                            <td>
                                @Html.DisplayFor(modelItem => item.Grade)
                            </td>
                        </tr>
                    }
                </table>
            </dd>
        </dl>
    </div>
    <p>
        @Html.ActionLink("Edit", "Edit", new { id = Model.ID }) |
        @Html.ActionLink("Back to List", "Index")
    </p>
    

    Si la sangría de código no es correcta después de pegar el código, presione Ctrl+K, Ctrl+D para formatearlo.

    Este código recorre en bucle las entidades en la propiedad de navegación Enrollments. Para cada entidad Enrollment de la propiedad, se muestra el título del curso y la calificación. El título del curso se recupera de la entidad Course almacenada en la propiedad de navegación Course de la entidad Enrollments. Todos estos datos se recuperan de la base de datos automáticamente cuando es necesario. Dicho de otra forma, aquí usa la carga diferida. No especificó la carga diligente para la propiedad de navegación Courses, por lo que las inscripciones no se recuperaron en la misma consulta que obtuvo los alumnos. En su lugar, la primera vez que intenta acceder a la propiedad de navegación Enrollments, se envía una nueva consulta a la base de datos para recuperar los datos. Puede leer más información sobre la carga diferida y la carga diligente en el tutorial Lectura de datos relacionados más adelante en esta serie.

  3. Para abrir la página de detalles, inicie el programa (Ctrl+F5), seleccione la pestaña Alumnos y, a continuación, haga clic en el vínculo de detalles de Alexander Carson (si presiona Ctrl+F5 mientras el archivo Details.cshtml está abierto, obtendrá un error HTTP 400. Esto se debe a que Visual Studio intenta ejecutar la página de detalles, pero sin que se haya accedido a ella desde un vínculo que especifica el alumno que se va a mostrar. Si esto sucede, quite "Student/Details" de la dirección URL e inténtelo de nuevo, o cierre el explorador, haga clic con el botón derecho en el proyecto y haga clic en Ver>Ver en el explorador).

    Verá la lista de cursos y calificaciones para el alumno seleccionado.

  4. Cierre el explorador.

Actualizar la página Create

  1. En Controllers\StudentController.cs, reemplace el método de acción HttpPostAttribute Create por el código siguiente. Este código agrega un bloque try-catch y quita ID del atributo BindAttribute del método con scaffolding:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create([Bind(Include = "LastName, FirstMidName, EnrollmentDate")]Student student)
    {
        try
        {
            if (ModelState.IsValid)
            {
                db.Students.Add(student);
                db.SaveChanges();
                return RedirectToAction("Index");
            }
        }
        catch (DataException /* dex */)
        {
            //Log the error (uncomment dex variable name and add a line here to write a log.
            ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
        }
        return View(student);
    }
    

    Este código agrega la entidad Student creada por el enlazador de modelos MVC de ASP.NET al conjunto de entidades Students y después guarda los cambios en la base de datos. El enlazador de modelos se refiere a la funcionalidad de ASP.NET MVC que facilita trabajar con datos enviados por un formulario; un enlazador de modelos convierte los valores de formulario enviados en tipos CLR y los pasa al método de acción en parámetros. En este caso, el enlazador de modelos crea instancias de una entidad Student mediante valores de propiedad de la colección Form.

    Se ha quitado ID del atributo Bind porque ID es el valor de clave principal que SQL Server establecerá automáticamente cuando se inserte la fila. La entrada del usuario no establece el valor ID.

    Advertencia de seguridad: el atributo ValidateAntiForgeryToken ayuda a evitar ataques de falsificación de solicitud entre sitios. Requiere una instrucción Html.AntiForgeryToken() correspondiente en la vista, que verá más adelante.

    El atributo Bind es una manera de proteger contra el exceso de publicación en escenarios de creación. Por ejemplo, suponga que la entidad Student incluye una propiedad Secret que no quiere que esta página web establezca.

    public class Student
    {
        public int ID { get; set; }
        public string LastName { get; set; }
        public string FirstMidName { get; set; }
        public DateTime EnrollmentDate { get; set; }
        public string Secret { get; set; }
    
        public virtual ICollection<Enrollment> Enrollments { get; set; }
    }
    

    Aunque no tenga un campo Secret en la página web, un hacker podría usar una herramienta como fiddler, o bien escribir código de JavaScript, para enviar un valor de formulario Secret. Sin el atributo BindAttribute para limitar los campos que el enlazador de modelos usa cuando crea una instancia Student, el enlazador de modelos seleccionaría ese valor de formulario Secret y lo usaría para crear la instancia de la entidad Student. Después, el valor que el hacker haya especificado para el campo de formulario Secret se actualizaría en la base de datos. En la imagen siguiente se muestra cómo la herramienta fiddler agrega el campo Secret (con el valor "OverPost") a los valores de formulario publicados.

    Recorte de pantalla en el que se muestra la pestaña Composer. En la esquina superior derecha, Execute está rodeado en color rojo. En la esquina inferior derecha, Secret equals Over Post está rodeado en color rojo.

    Después, el valor "OverPost" se agregaría correctamente a la propiedad Secret de la fila insertada, aunque no hubiera previsto que la página web pudiera establecer esa propiedad.

    Es mejor usar el parámetro Include con el atributo Bind para enumerar explícitamente los campos. También es posible usar el parámetro Exclude para bloquear los campos que desea excluir. La razón Include más segura es que al agregar una nueva propiedad a la entidad, una lista Exclude no protege el nuevo campo automáticamente.

    Puede evitar la publicación excesiva en escenarios de edición si primero lee la entidad desde la base de datos y después llama a TryUpdateModel, pasando una lista de propiedades permitidas de manera explícita. Es el método que se usa en estos tutoriales.

    Una manera alternativa de evitar la publicación excesiva que muchos desarrolladores prefieren consiste en usar modelos de vista en lugar de clases de entidad con el enlace de modelos. Incluya en el modelo de vista solo las propiedades que quiera actualizar. Una vez que haya finalizado el enlazador de modelos de MVC, copie las propiedades del modelo de vista a la instancia de entidad, opcionalmente con una herramienta como AutoMapper. Use db.Entry en la instancia de entidad para establecer su estado en Inalterada y, después, establezca Property("PropertyName").IsModified en true en todas las propiedades de entidad que se incluyan en el modelo de vista. Este método funciona tanto en escenarios de edición como de creación.

    Aparte del atributo Bind, el bloque try-catch es el único cambio que se ha realizado en el código con scaffolding. Si se detecta una excepción derivada de DataException mientras se guardan los cambios, se muestra un mensaje de error genérico. En ocasiones, las excepciones DataException se deben a algo externo a la aplicación y no a un error de programación, por lo que se recomienda al usuario que vuelva a intentarlo. Aunque no se ha implementado en este ejemplo, en una aplicación de producción de calidad se debería registrar la excepción. Para obtener más información, vea la sección Registro para obtener información de Supervisión y telemetría (creación de aplicaciones de nube reales con Azure).

    El código de Views\Student\Create.cshtml es similar al que vio en Details.cshtml, excepto que los asistentes EditorFor y ValidationMessageFor se usan para cada campo en lugar de DisplayFor. Este es el código pertinente:

    <div class="form-group">
        @Html.LabelFor(model => model.LastName, new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.LastName)
            @Html.ValidationMessageFor(model => model.LastName)
        </div>
    </div>
    

    Create.cshtml también incluye @Html.AntiForgeryToken(), que funciona con el atributo ValidateAntiForgeryToken en el controlador para contribuir a evitar ataques de falsificación de solicitud entre sitios.

    No es preciso realizar cambios en Create.cshtml.

  2. Para ejecutar la página, inicie el programa, seleccione la pestaña Alumnos y, a continuación, haga clic en Crear nuevo.

  3. Escriba los nombres y una fecha no válida y haga clic en Crear para ver el mensaje de error.

    Es la validación del lado servidor que obtendrá de forma predeterminada. En un tutorial posterior, verá cómo agregar atributos que generan código para la validación del lado cliente. En el siguiente código resaltado se muestra la comprobación de validación del modelo en el método Create.

    if (ModelState.IsValid)
    {
        db.Students.Add(student);
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    
  4. Cambie la fecha por un valor válido y haga clic en Crear para ver el alumno nuevo en la página Index.

  5. Cierre el explorador.

Actualizar el método HttpPost Edit

  1. Reemplace el método de acción HttpPostAttribute Edit por el código siguiente:

    [HttpPost, ActionName("Edit")]
    [ValidateAntiForgeryToken]
    public ActionResult EditPost(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        var studentToUpdate = db.Students.Find(id);
        if (TryUpdateModel(studentToUpdate, "",
           new string[] { "LastName", "FirstMidName", "EnrollmentDate" }))
        {
            try
            {
                db.SaveChanges();
    
                return RedirectToAction("Index");
            }
            catch (DataException /* dex */)
            {
                //Log the error (uncomment dex variable name and add a line here to write a log.
                ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
            }
        }
        return View(studentToUpdate);
    }
    

    Nota:

    En Controllers\StudentController.cs, el método HttpGet Edit (el que no tiene el atributo HttpPost) usa el método Find para recuperar la entidad Student seleccionada, como se vio en el método Details. No es necesario cambiar este método.

    Estos cambios implementan un procedimiento recomendado de seguridad para evitar la publicación excesiva. El proveedor de scaffolding generó un atributo Bind y agregó la entidad creada por el enlazador de modelos a la entidad establecida con una marca modificada. Ese código ya no se recomienda porque el atributo Bind borra los datos ya existentes en los campos que no se enumeran en el parámetro Include. En el futuro, el proveedor de scaffolding del controlador MVC se actualizará para que no genere atributos Bind de los métodos Edit.

    El código nuevo lee la entidad existente y llama a TryUpdateModel para actualizar los campos de entrada de usuario en los datos de formulario publicados. El seguimiento de cambios automático de Entity Framework establece la marca EntityState.Modified en la entidad. Cuando se llama al método SaveChanges, la marca Modified hace que Entity Framework cree instrucciones SQL para actualizar la fila de la base de datos. Los conflictos de simultaneidad se ignoran y todas las columnas de la fila de la base de datos se actualizan, incluidas aquellas que el usuario no cambió (en un tutorial posterior se muestra cómo controlar los conflictos de simultaneidad y, si solo desea actualizar campos individuales en la base de datos, puede establecer la entidad en EntityState.Unchanged y establecer los campos individuales en EntityState.Modified).

    Para evitar la publicación excesiva, los campos que quiera que se puedan actualizar por la página de edición se enumeran en los parámetros TryUpdateModel. Actualmente no se está protegiendo ningún campo adicional, pero enumerar los campos que quiere que el enlazador de modelos enlace garantiza que, si en el futuro agrega campos al modelo de datos, se protejan automáticamente hasta que los agregue aquí de forma explícita.

    Como resultado de estos cambios, la firma de método del método HttpPost Edit es la misma que la del método HttpGet Edit; por tanto, se ha cambiado el nombre del método EditPost.

    Sugerencia

    Estados de entidad y los métodos Attach y SaveChanges

    El contexto de la base de datos realiza el seguimiento de si las entidades en memoria están sincronizadas con sus filas correspondientes en la base de datos, y esta información determina lo que ocurre cuando se llama al método SaveChanges. Por ejemplo, cuando se pasa una nueva entidad al método Add, el estado de esa entidad se establece en Added. Después, cuando se llama al método SaveChanges, el contexto de la base de datos emite un comando INSERT de SQL.

    Una entidad puede estar en uno de los estados siguientes:

    • Added. La entidad no existe todavía en la base de datos. El método SaveChanges debe emitir una instrucción INSERT.
    • Unchanged. No es necesario hacer nada con esta entidad mediante el método SaveChanges. Al leer una entidad de la base de datos, la entidad empieza con este estado.
    • Modified. Se han modificado algunos o todos los valores de propiedad de la entidad. El método SaveChanges debe emitir una instrucción UPDATE.
    • Deleted. La entidad se ha marcado para su eliminación. El método SaveChanges debe emitir una instrucción DELETE.
    • Detached. El contexto de base de datos no está realizando el seguimiento de la entidad.

    En una aplicación de escritorio, los cambios de estado normalmente se establecen de forma automática. En un tipo de aplicación de escritorio, se lee una entidad y se realizan cambios en algunos de sus valores de propiedad. Esto hace que su estado de entidad cambie automáticamente a Modified. Después, cuando se llama a SaveChanges, Entity Framework genera una instrucción UPDATE de SQL que solo actualiza las propiedades reales que se hayan cambiado.

    La naturaleza desconectada de las aplicaciones web no permite esta secuencia continua. La instancia de DbContext que lee una entidad se elimina después de representar una página. Cuando se llama al método de acción HttpPost Edit, se realiza una nueva solicitud y se tiene una nueva instancia de DbContext, por lo que debe establecer manualmente el estado de la entidad en Modified.. Después, al llamar a SaveChanges, Entity Framework actualiza todas las columnas de la fila de base de datos, ya que el contexto no tiene ninguna manera de saber qué propiedades se han cambiado.

    Si quiere que la instrucción Update de SQL actualice solo los campos que el usuario ha cambiado realmente, puede guardar los valores originales de alguna manera (como campos ocultos) para que estén disponibles cuando se llame al método HttpPost Edit. Después puede crear una entidad Student con los valores originales, llamar al método Attach con esa versión original de la entidad, actualizar los valores de la entidad con los valores nuevos y luego llamar a SaveChanges.. Para obtener más información, consulte Estados de entidad y SaveChanges y Datos locales.

    El código HTML y de Razor de Views\Student\Edit.cshtml es similar a lo que vio en Create.cshtml y no es necesario ningún cambio.

  2. Para ejecutar la página, inicie el programa, seleccione la pestaña Alumnos y, a continuación, haga clic en un hipervínculo de edición.

  3. Cambie algunos de los datos y haga clic en Guardar. Verá los datos modificados en la página de índice.

  4. Cierre el explorador.

Actualizar la página Delete

En Controllers\StudentController.cs, el código de plantilla del método HttpGetAttribute Delete usa el método Find para recuperar la entidad Student seleccionada, como se ha visto en los métodos Details y Edit. Pero para implementar un mensaje de error personalizado cuando se produce un error en la llamada a SaveChanges, agregará funcionalidad a este método y su vista correspondiente.

Como se vio para las operaciones de actualización y creación, las operaciones de eliminación requieren dos métodos de acción. El método que se llama en respuesta a una solicitud GET muestra una vista que proporciona al usuario la oportunidad de aprobar o cancelar la operación de eliminación. Si el usuario la aprueba, se crea una solicitud POST. Cuando esto ocurre, se llama al método HttpPost Delete y, después, ese método es el que realiza la operación de eliminación.

Agregará un bloque try-catch al método HttpPostAttribute Delete para controlar los errores que se puedan producir cuando se actualice la base de datos. Si se produce un error, el método HttpPostAttribute Delete llama al método HttpGetAttribute Delete, y pasa un parámetro que indica que se ha producido un error. Después, el método HttpGetAttribute Delete vuelve a mostrar la página de confirmación junto con el mensaje de error, lo que da al usuario la oportunidad de cancelar la acción o volver a intentarlo.

  1. Reemplace el método de acción HttpGetAttribute Delete con el código siguiente, que administra los informes de errores:

    public ActionResult Delete(int? id, bool? saveChangesError=false)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        if (saveChangesError.GetValueOrDefault())
        {
            ViewBag.ErrorMessage = "Delete failed. Try again, and if the problem persists see your system administrator.";
        }
        Student student = db.Students.Find(id);
        if (student == null)
        {
            return HttpNotFound();
        }
        return View(student);
    }
    

    Este código acepta un parámetro opcional que indica si se llamó al método después de un error al guardar los cambios. Este parámetro es false cuando se llama al método HttpGet Delete sin un error anterior. Cuando se llama por medio del método HttpPost Delete en respuesta a un error de actualización de base de datos, el parámetro es true y se pasa un mensaje de error a la vista.

  2. Reemplace el método de acción HttpPostAttribute Delete (denominado DeleteConfirmed) por el código siguiente, que realiza la operación de eliminación real y captura los errores de actualización de la base de datos.

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Delete(int id)
    {
        try
        {
            Student student = db.Students.Find(id);
            db.Students.Remove(student);
            db.SaveChanges();
        }
        catch (DataException/* dex */)
        {
            //Log the error (uncomment dex variable name and add a line here to write a log.
            return RedirectToAction("Delete", new { id = id, saveChangesError = true });
        }
        return RedirectToAction("Index");
    }
    

    Este código recupera la entidad seleccionada y después llama al método Remove para establecer el estado de la entidad en Deleted. Cuando se llama a SaveChanges, se genera un comando DELETE de SQL. También ha cambiado el nombre del método de acción de DeleteConfirmed a Delete. El código al que se aplicó la técnica scaffolding ha asignado al método Delete de HttpPost el nombre DeleteConfirmed para proporcionar al método HttpPost una firma única. (El CLR requiere métodos sobrecargados para tener parámetros de método diferentes). Ahora que las firmas son únicas, puede ceñirse a la convención MVC y usar el mismo nombre para los métodos de eliminación HttpPost y HttpGet.

    Si mejorar el rendimiento de una aplicación de gran volumen es una prioridad, podría evitar una consulta SQL innecesaria para recuperar la fila mediante el reemplazo de las líneas de código que llaman a los métodos Find y Remove por el código siguiente:

    Student studentToDelete = new Student() { ID = id };
    db.Entry(studentToDelete).State = EntityState.Deleted;
    

    Este código crea una instancia de una entidad Student solo con el valor de clave principal y después estableciendo el estado de la entidad en Deleted. Eso es todo lo que necesita Entity Framework para eliminar la entidad.

    Como se ha indicado, el método HttpGet Delete no elimina los datos. Realizar una operación de eliminación en respuesta a una solicitud GET (o con este propósito, efectuar una operación de edición, creación o cualquier otra operación que modifique los datos) presenta un riesgo de seguridad.

  3. En Views/Student/Delete.cshtml, agregue un mensaje de error entre los títulos h2 y h3, como se muestra en el ejemplo siguiente:

    <h2>Delete</h2>
    <p class="error">@ViewBag.ErrorMessage</p>
    <h3>Are you sure you want to delete this?</h3>
    
  4. Para ejecutar la página, inicie el programa, seleccione la pestaña Alumnos y, a continuación, haga clic en un hipervínculo de eliminación.

  5. Elija Eliminar en la página en la que se indica ¿Seguro que quiere eliminarlo?

    Se mostrará la página de índice sin el alumno eliminado (verá un ejemplo del código de control de errores en funcionamiento en el tutorial sobre la simultaneidad).

Cerrar conexiones de bases de datos

Para cerrar conexiones de bases de datos y liberar los recursos que contienen lo antes posible, elimine la instancia de contexto cuando haya terminado. Ese es el motivo por el que el código con scaffolding proporciona un método Dispose al final de la clase StudentController en StudentController.cs, como se muestra en el ejemplo siguiente:

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        db.Dispose();
    }
    base.Dispose(disposing);
}

La clase de Controller base ya implementa la interfaz IDisposable, por lo que este código simplemente agrega una invalidación al método Dispose(bool) para eliminar explícitamente la instancia de contexto.

Controlar transacciones

De forma predeterminada, Entity Framework implementa las transacciones de manera implícita. En escenarios donde se realizan cambios en varias filas o tablas, y después se llama a SaveChanges, Entity Framework se asegura automáticamente de que todos los cambios se realicen correctamente o se produzca un error en todos ellos. Si primero se realizan algunos cambios y después se produce un error, los cambios se revierten automáticamente. Para escenarios donde se necesita más control, por ejemplo, si se quiere incluir operaciones realizadas fuera de Entity Framework en una transacción, consulte Trabajar con transacciones.

Obtención del código

Descargar el proyecto completado

Recursos adicionales

Ahora tiene un conjunto completo de páginas que realizan sencillas operaciones CRUD para entidades Student. Ha usado asistentes MVC para generar elementos de interfaz de usuario para campos de datos. Para obtener más información sobre los asistentes MVC, consulte Representar un formulario mediante asistentes de HTML (el artículo es para MVC 3, pero sigue siendo pertinente para MVC 5).

Encontrará vínculos a otros recursos de EF 6 en Acceso a datos de ASP.NET: Recursos recomendados.

Pasos siguientes

En este tutorial ha:

  • Se ha creado una página de detalles
  • Actualizado la página Create
  • Se ha actualizado el método HttpPost Edit
  • Actualizado la página Delete
  • Cerrado conexiones de bases de datos
  • Se han controlado las transacciones

Pase al siguiente artículo para aprender a agregar ordenación, filtrado y paginación al proyecto.