Traducción: Primeros pasos con Entity Framework 6 de MVC5 (12) - Uso de funciones avanzadas para aplicaciones ASP.NET MVC

Use funciones avanzadas para aplicaciones ASP.NET MVC

Esta es una traducción del tutorial oficial de Microsoft Comenzando con Entity Framework 6 Code Primero usando la serie MVC 5, aquí está el duodécimo: Uso de funciones avanzadas para aplicaciones ASP.NET MVC

: :Escenarios de Advanced Entity Framework 6 para una aplicación web MVC 5


En el tutorial anterior, ha implementado la herencia. Este tutorial presenta las características avanzadas que se pueden usar cuando se utiliza el Código de Entity Framework First para desarrollar aplicaciones web ASP.NET, incluidas las siguientes partes:

  • Ejecutar consulta SQL sin procesar
  • Realizar consultas sin seguimiento
  • Verifique el SQL enviado a la base de datos

Además, este tutorial proporciona una breve introducción a los siguientes temas y proporciona enlaces de referencia:

  • Almacenamiento y modo de trabajo de la unidad
  • Clase de agente
  • Monitoreo automático de cambios
  • Verificación automática
  • Herramienta Visua Studio Entity Framework
  • Código fuente del marco de la entidad

Para la mayoría de los temas tratados en este tutorial, utilizará las páginas web que ha creado y utilizará el SQL original para las actualizaciones por lotes. Luego creará una nueva página para actualizar los créditos de todos los cursos en la base de datos.

actualizar los créditos del curso

Ejecutar consulta SQL sin procesar

La API de Entity Framework Code First contiene métodos que le permiten enviar comandos SQL directamente a la base de datos. Tienes las siguientes opciones:

  • Use el método DbSet.SqlQuery para consultar y devolver el tipo de entidad. El tipo de objeto devuelto debe ser el objeto DbSet esperado, el contexto de la base de datos los rastreará automáticamente. A menos que desactive el seguimiento. (Consulte el método AsNoTracking en la siguiente sección )

  • Use el método Database.SqlQuery para consultar y devolver tipos que no sean de entidad. El contexto de la base de datos no rastreará el objeto devuelto, incluso si utiliza este método para recuperar el tipo de entidad.

  • Database.ExecuteSqlCommand se usa para comandos de tipo que no son de consulta.

Una de las ventajas de usar Entity Framework es que le permite implementar un método específico para acceder a los datos sin tener que ingresar manualmente mucho código. Al generar automáticamente consultas y comandos SQL, se libera de la tediosa codificación manual. Pero en casos especiales, es posible que deba ejecutar consultas SQL específicas que se crean manualmente, estos métodos pueden lograr esta función y proporcionarle un manejo de excepciones.

Cuando ejecuta comandos SQL con frecuencia en aplicaciones web, debe tomar las precauciones necesarias para proteger su sitio de los ataques de inyección SQL. Una forma es utilizar consultas parametrizadas para garantizar que las cadenas de las páginas web no se interpreten como comandos SQL. En este tutorial, cuando use un usuario para ingresar una consulta, usará una consulta parametrizada.

Llame una consulta para devolver la entidad

DbSet<TEntity>La clase proporciona un método que puede usar para ejecutar una consulta y devolver un tipo de entidad. Para observar cómo funciona este método, debe realizar algunos cambios en el método Detalles en el controlador del Departamento.

En DepartmentController.cs, reemplace el método Detalles con el siguiente código, resaltando los cambios que deben realizarse:

public async Task<ActionResult> Details(int? id)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }

    // Commenting out original code to show how to use a raw SQL query.
    //Department department = await db.Departments.FindAsync(id);

    // Create and execute raw SQL query.
    string query = "SELECT * FROM Department WHERE DepartmentID = @p0";
    Department department = await db.Departments.SqlQuery(query, id).SingleOrDefaultAsync();

    if (department == null)
    {
        return HttpNotFound();
    }
    return View(department);
}

Para verificar que el nuevo código funciona correctamente, ejecute la aplicación, vaya a la página del departamento y haga clic en los detalles de un departamento.

Departamento

Puedes ver que todo funciona como antes.

Llame una consulta para devolver otros tipos de objetos

En el tutorial anterior, creó una cuadrícula de estadísticas de estudiantes para mostrar el número de estudiantes registrados en cada fecha de registro. Este código usa LINQ para operar:

var data = from student in db.Students
           group student by student.EnrollmentDate into dateGroup
           select new EnrollmentDateGroup()
           {
               EnrollmentDate = dateGroup.Key,
               StudentCount = dateGroup.Count()
           };

Suponga que desea escribir código SQL directamente para esta consulta en lugar de usar LINQ. Debe ejecutar una consulta para devolver objetos que no sean tipos de entidad, lo que significa que debe usar el método Database.SqlQuery.

En HomeController.cs, reemplace el método Acerca de con el siguiente código. La parte resaltada muestra los cambios que deben realizarse:

public ActionResult About()
{
    // Commenting out LINQ to show how to do the same thing in SQL.
    //IQueryable<EnrollmentDateGroup> = from student in db.Students
    //           group student by student.EnrollmentDate into dateGroup
    //           select new EnrollmentDateGroup()
    //           {
    //               EnrollmentDate = dateGroup.Key,
    //               StudentCount = dateGroup.Count()
    //           };

    // SQL version of the above LINQ code.
    string query = "SELECT EnrollmentDate, COUNT(*) AS StudentCount "
        + "FROM Person "
        + "WHERE Discriminator = 'Student' "
        + "GROUP BY EnrollmentDate";
    IEnumerable<EnrollmentDateGroup> data = db.Database.SqlQuery<EnrollmentDateGroup>(query);

    return View(data.ToList());
}

Ejecute la página, mostrará los mismos datos que antes.

estadísticas del cuerpo estudiantil

Consulta de actualización de llamada

Suponga que el administrador desea poder realizar operaciones por lotes en la base de datos, como cambiar créditos para cada curso. Si la escuela tiene una gran cantidad de cursos, es indudablemente muy ineficiente actualizar cada curso por separado. En esta sección, implementará una página web que permita a los usuarios modificar los créditos de todos los cursos y realizar este cambio utilizando la instrucción SQL Update, como se muestra a continuación:

actualizar los créditos del curso

En CourseController.cs, agregue el método UpdateCourseCredits de HttpGet y HttpPost:

public ActionResult UpdateCourseCredits()
{
    return View();
}

[HttpPost]
public ActionResult UpdateCourseCredits(int? multiplier)
{
    if (multiplier != null)
    {
        ViewBag.RowsAffected = db.Database.ExecuteSqlCommand("UPDATE Course SET Credits = Credits * {0}", multiplier);
    }
    return View();
}

Cuando el controlador procesa la solicitud HttpGet, ViewBag.RowsAffected no devolverá ningún valor. La vista mostrará un cuadro de texto vacío y un botón de enviar.

Cuando se hace clic en el botón de actualización, se llama al método HttpPost para obtener el valor ingresado en el cuadro de texto. El código ejecuta SQL para actualizar el curso y devuelve el número de filas afectadas en ViewBag.RowsAffected. Cuando la vista obtiene el valor de la variable, mostrará un mensaje para explicar la cantidad de cursos que se han actualizado en lugar del cuadro de texto y el botón de enviar, como se muestra en la siguiente figura:

actualizar los créditos del curso

En CourseController.cs, haga clic con el botón derecho en el método UpdateCourseCredits y agregue una vista:

agregar vista

Use el siguiente código para reemplazar la vista:

@model ContosoUniversity.Models.Course

@{
    ViewBag.Title = "UpdateCourseCredits";
}

<h2>Update Course Credits</h2>

@if (ViewBag.RowsAffected == null)
{
    using (Html.BeginForm())
    {
        <p>
            Enter a number to multiply every course's credits by: @Html.TextBox("multiplier")
        </p>
        <p>
            <input type="submit" value="Update" />
        </p>
    }
}
@if (ViewBag.RowsAffected != null)
{
    <p>
        Number of rows updated: @ViewBag.RowsAffected
    </p>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>

Ejecute la aplicación, agregue "/ UpdateCourseCredits" al final de la barra de direcciones del navegador, como Http: // localhost: xxxx / UpdateCourseCredits , abra la página e ingrese un número en el cuadro de texto:

actualizar los créditos del curso

Haga clic en Actualizar y verá los cursos afectados:

actualizar los créditos del curso

Luego regrese a la lista, verá que todos los cursos se han actualizado:

cursos

Para obtener más información sobre el uso de consultas SQL sin formato, consulte Consultas SQL sin formato en MSDN .

Consulta sin seguimiento

Cuando el contexto de la base de datos recupera filas de datos y crea objetos de entidad, por defecto rastrea si las entidades en memoria están sincronizadas con la base de datos. Cuando actualiza una entidad, los datos en la memoria actúan como un caché. Este tipo de almacenamiento en caché a menudo no está disponible en las aplicaciones web porque las instancias de contexto suelen ser de corta duración (se crea una nueva instancia para cada solicitud), y el contexto a menudo las destruye después de leer las entidades y usarlas .

Puede usar el método AsNoTracking para deshabilitar el seguimiento de objetos de entidad en la memoria. En los siguientes escenarios típicos, es posible que deba hacer esto:

  • Es necesario recuperar una gran cantidad de datos, y desactivar el seguimiento puede mejorar significativamente el rendimiento.

  • Debe adjuntar una entidad para actualizarla, pero es el mismo objeto de entidad obtenido previamente para diferentes propósitos. Debido a que el contexto de la base de datos ya rastrea a la entidad, no puede adjuntarla para realizar cambios. En este caso, debe usar la opción AsNoTracking para consultas anteriores.

Verifique el SQL enviado a la base de datos

A veces es útil ver las consultas SQL que realmente se envían a la base de datos. En el tutorial anterior, viste cómo usar el código interceptor para realizar este trabajo. Ahora verás cómo no usar el interceptor Método Para probar este método, verificará una consulta simple y observará las adiciones, como la carga previa, el filtrado y la clasificación para ver qué sucedió.

En CourseController.cs, reemplace el original con el siguiente código para detener la precarga:

public ActionResult Index()
{
    var courses = db.Courses;
    var sql = courses.ToString();
    return View(courses.ToList());
}

Luego establezca un punto de interrupción en la declaración de retorno y presione F5 para ejecutar el proyecto en modo de depuración, seleccione la página de índice del curso, cuando el código llegue al punto de interrupción, verifique la variable de consulta, verá la consulta SQL enviada, Es una simple declaración de selección.

{SELECT 
[Extent1].[CourseID] AS [CourseID], 
[Extent1].[Title] AS [Title], 
[Extent1].[Credits] AS [Credits], 
[Extent1].[DepartmentID] AS [DepartmentID]
FROM [Course] AS [Extent1]}

Puede usar herramientas de visualización de texto para ver SQL en la ventana de monitoreo.

depurar

Ahora se agrega una lista desplegable a la página de índice del curso, que el usuario puede usar para filtrar departamentos específicos. Utilizará el título para ordenar y especificar la precarga de las propiedades de navegación del sistema.

En CourseController.cs, reemplace el método Index con el siguiente código:

public ActionResult Index(int? SelectedDepartment)
{
    var departments = db.Departments.OrderBy(q => q.Name).ToList();
    ViewBag.SelectedDepartment = new SelectList(departments, "DepartmentID", "Name", SelectedDepartment);
    int departmentID = SelectedDepartment.GetValueOrDefault();

    IQueryable<Course> courses = db.Courses
        .Where(c => !SelectedDepartment.HasValue || c.DepartmentID == departmentID)
        .OrderBy(d => d.CourseID)
        .Include(d => d.Department);
    var sql = courses.ToString();
    return View(courses.ToList());
}

Todavía establece un punto de interrupción en el regreso.

Este método recibe el valor seleccionado en la lista desplegable. Si no se selecciona ningún elemento, este parámetro es nulo.

Una colección SelectList que contiene todos los departamentos se pasa a la lista desplegable de vistas. Los parámetros pasados ​​al constructor SelectList especifican el nombre del campo de valor, el nombre del campo de texto y el elemento seleccionado.

Para el método Get del almacén del curso, el código especifica una expresión de filtro para el atributo de navegación Departamento, una clasificación y carga diferida. Si no se selecciona ningún elemento en la tabla desplegable, la expresión del filtro siempre devuelve verdadero.

En Views \ Course \ Index.cshtml, antes de la etiqueta de inicio de la tabla, inserte el siguiente código para crear la lista desplegable y el botón de enviar:

@using (Html.BeginForm())
{
    <p>Select Department: @Html.DropDownList("SelectedDepartment","All")   
    <input type="submit" value="Filter" /></p>
}

Ejecute la página de índice, continúe ejecutándose cuando se encuentre un punto de interrupción para mostrar la página, seleccione un departamento de la lista desplegable y haga clic en filtro:

cursos

Vea la instrucción SQL de acuerdo con el método en este momento, y verá un SQL que contiene la consulta de unión interna:

SELECT 
    [Project1].[CourseID] AS [CourseID], 
    [Project1].[Title] AS [Title], 
    [Project1].[Credits] AS [Credits], 
    [Project1].[DepartmentID] AS [DepartmentID], 
    [Project1].[DepartmentID1] AS [DepartmentID1], 
    [Project1].[Name] AS [Name], 
    [Project1].[Budget] AS [Budget], 
    [Project1].[StartDate] AS [StartDate], 
    [Project1].[InstructorID] AS [InstructorID], 
    [Project1].[RowVersion] AS [RowVersion]
    FROM ( SELECT 
        [Extent1].[CourseID] AS [CourseID], 
        [Extent1].[Title] AS [Title], 
        [Extent1].[Credits] AS [Credits], 
        [Extent1].[DepartmentID] AS [DepartmentID], 
        [Extent2].[DepartmentID] AS [DepartmentID1], 
        [Extent2].[Name] AS [Name], 
        [Extent2].[Budget] AS [Budget], 
        [Extent2].[StartDate] AS [StartDate], 
        [Extent2].[InstructorID] AS [InstructorID], 
        [Extent2].[RowVersion] AS [RowVersion]
        FROM  [dbo].[Course] AS [Extent1]
        INNER JOIN [dbo].[Department] AS [Extent2] ON [Extent1].[DepartmentID] = [Extent2].[DepartmentID]
        WHERE @p__linq__0 IS NULL OR [Extent1].[DepartmentID] = @p__linq__1
    )  AS [Project1]
    ORDER BY [Project1].[CourseID] ASC

Ahora puede ver que la consulta anterior es una consulta conectada que carga datos de departamento y curso y contiene una cláusula WHERE.

Quitar elvar sql = conrses.ToString();

Almacenamiento y modo de trabajo de la unidad

Muchos desarrolladores escriben código como paquete para implementar el modo de almacenamiento y unidad de trabajo de Entity Framework. Estos patrones crean una capa de abstracción entre la capa de lógica de negocios y la capa de acceso a datos. La implementación de estos patrones puede ayudar a su aplicación a aislarse de los cambios en el almacenamiento de datos y facilitar el desarrollo automatizado de pruebas unitarias. Sin embargo, escribir código adicional para implementar estos patrones para programas que usan Entity Framework no es la mejor opción por varias razones:

  • La clase de contexto Entity Framework en sí misma puede aislar su código del almacenamiento de datos de código específico.

  • Cuando utiliza Entity Framework, la clase de contexto Entity Framework para las operaciones de actualización de la base de datos se puede utilizar como una unidad de clase de trabajo.

  • La funcionalidad introducida en la versión de Entity Framework 6 le permite realizar una prueba de unidad sin escribir código de almacenamiento.

Para obtener información detallada sobre cómo implementar los modos de almacenamiento y funcionamiento de la unidad, consulte la versión Entity Framework 5 de esta serie de tutoriales . Para saber cómo ejecutar el controlador de prueba unitaria en la versión Entity Framework 6, consulte:

Clase de agente

Cuando Entity Framework crea una instancia de entidad (por ejemplo, cuando ejecuta una consulta), siempre crea un proxy como un objeto de entidad generado dinámicamente derivado de la entidad. Por ejemplo, en las siguientes dos capturas de pantalla del depurador, en la primera imagen, verá una variable de estudiante que se espera sea del tipo Estudiante. Después de crear una instancia de la entidad, verá la clase proxy en la segunda imagen.

controlador estudiantil

controlador estudiantil

La clase proxy reescribe algunos atributos virtuales de la entidad para insertar ganchos que realizan acciones automáticamente al acceder al atributo. Una de las funciones que utiliza este mecanismo es la carga diferida.

La mayoría de las veces no notará al agente, pero hay excepciones:

  • En algunos casos, es posible que desee evitar que Entity Framework cree instancias de proxy. Por ejemplo, generalmente desea serializar una entidad de clase POCO, no una clase proxy. Una forma de evitar problemas de serialización es serializar objetos de transferencia de datos (DTO) en lugar de objetos de entidad, como el uso de API web con Entity Framework . Otro método es deshabilitar la creación de proxy .

  • Cuando crea una instancia de una clase de entidad utilizando el nuevo operador, lo que obtiene no es una instancia de proxy. Esto significa que no puede obtener capacidades como la carga diferida y el seguimiento automático. Esto suele ser bueno: por lo general, no necesita una carga diferida porque necesita crear una nueva entidad que no existe en la base de datos. Cuando marca explícitamente una entidad como Agregada, generalmente no necesita el seguimiento de modificaciones. Sin embargo, si necesita una carga diferida y necesita cambiar el seguimiento, puede crear un nuevo objeto de entidad a través de un proxy utilizando el método Create de la clase DbSet .

  • Es posible que desee obtener un tipo de entidad real de un tipo de proxy. El método GetObjectType de la clase ObjectContext se puede utilizar para obtener el tipo de entidad real del tipo de proxy.

Para obtener más información, consulte Trabajar con proxies en MSDN .

Monitoreo automático de cambios

Entity Framework utiliza la comparación del valor actual y el valor original de una entidad para determinar si una entidad ha cambiado (y, por lo tanto, debe enviarse a la base de datos para realizar actualizaciones). Cuando se consulta o agrega una entidad, se guarda el valor original. Algunos métodos que conducen a la supervisión automática de cambios son los siguientes:

  • DbSet.Find
  • DbSet.Local
  • DbSet.Remove
  • DbSet.Add
  • DbSet.Attach
  • DbContext.Savechanges
  • DbContext.GetValidationErrors
  • DbContext.Entry
  • DbChangeTracker.Entries

Si está rastreando una gran cantidad de entidades y llama a estos métodos varias veces en un ciclo, puede desactivar temporalmente la supervisión automática de cambios utilizando la propiedad AutoDetectChangesEnabled para obtener mejoras en el rendimiento del programa.

Verificación automática

Cuando llama al método SaveChanges, de forma predeterminada, Entity Framework verificará todas las propiedades en todas las entidades modificadas antes de actualizar a la base de datos. Si actualiza una gran cantidad de entidades y ha verificado los datos, este trabajo es innecesario y puede obtener menos tiempo de procesamiento desactivando la verificación temporalmente. Puede usar la propiedad ValidateOnSaveEnabled .

Entity Framework Power Tools

Entity Framework Power Tools es una extensión VS simple que puede usar para crear el diagrama del modelo de datos que se muestra en este tutorial. La herramienta también puede realizar otras tareas, como generar clases de entidad basadas en tablas de bases de datos existentes cuando usa Code First. Después de instalar la herramienta, verá algunas opciones adicionales en el menú contextual. Por ejemplo, al hacer clic con el botón derecho en la clase de contexto del Explorador de soluciones, obtendrá una opción para generar un gráfico. No puede modificar el modelo de datos en el diagrama de relación cuando usa Code First, pero puede mover el diagrama para que sea más fácil de entender.

explorador de la solución

contexto escolar

Código fuente del marco de la entidad

Puede obtener el código fuente de Entity Framework 6 en http://entityframework.codeplex.com/ . Además del código fuente, puede generar, rastrear problemas, explorar funciones y más. Puede enviar errores y contribuir con sus propias mejoras a Código fuente del marco de la entidad.

Aunque el código fuente está abierto, el marco físico es un producto totalmente compatible con Microsoft. El equipo de Microsoft Entity Framework continuará recibiendo comentarios y probando cambios para garantizar la calidad de cada versión.

Resumen

De esta manera, se completa una serie de tutoriales sobre el uso de Entity Framework en las aplicaciones ASP.NET MVC. Para obtener más información sobre cómo usar Entity Framework, consulte la página de documentación de EF en MSDN y los recursos recomendados de acceso a datos de ASP.NET .

Para saber cómo implementarlo después de compilar la aplicación, consulte los recursos recomendados de implementación web de ASP.NET .

Para obtener más información sobre MVC, consulte los Recursos recomendados por ASP.NET MVC .

Gracias

  • Tom Dykstra escribió la versión original de este tutorial basada en Entity Framework 5, y escribió el tutorial basado en ella. Es escritor sénior de programación en el equipo de herramientas y plataforma web de Microsoft.

  • Rick Anderson ha trabajado mucho en los tutoriales de Entity Framework 5 y MVC4 y es coautor de la actualización de Entity Framework 6. Es escritor sénior de programación para Microsoft Azure y MVC.

  • Rowan Miller y otros equipos de Entity Framework revisaron el tutorial y depuraron una gran cantidad de errores.

Información del autor

tom-dykstra Tom Dykstra -Tom Dykstra es un programador senior y escritor en el equipo de Microsoft Web Platform and Tools.

Publicó 40 artículos originales · 25 alabanzas · 100,000+ vistas

Supongo que te gusta

Origin blog.csdn.net/yym373872996/article/details/69668682
Recomendado
Clasificación