Introducción a Entity Framework 4.0 Database First y ASP.NET 4 Web Forms: parte 3

por Tom Dykstra

La aplicación web de ejemplo de Contoso University muestra cómo crear aplicaciones ASP.NET Web Forms utilizando Entity Framework 4.0 y Visual Studio 2010. Para obtener información sobre la serie de tutoriales, consulte el primer tutorial de la serie

Filtrado, ordenación y agrupación de datos

En el tutorial anterior usó el control EntityDataSource para mostrar y editar datos. En este tutorial filtrará, ordenará y agrupará los datos. Al hacerlo estableciendo las propiedades del control EntityDataSource, la sintaxis es diferente de otros controles de origen de datos. Sin embargo, como verá, puede usar el control QueryExtender para minimizar estas diferencias.

Cambiará la página Students.aspx para filtrar los alumnos, ordenar por nombre y buscar en nombre. También cambiará la página de Courses.aspx para mostrar cursos para el departamento seleccionado y buscar cursos por nombre. Por último, agregará estadísticas de alumnos a la página de About.aspx.

Screenshot of the Internet Explorer window, which is showing the Student List view with a table of students.

Screenshot of the Internet Explorer window, which is showing the Courses by Department and Courses by Name views.

Screenshot of the Internet Explorer window, which is showing the Student Body Statistics view with a table of enrollment dates.

Screenshot of the Internet Explorer window, which is showing the Find Students by Name view with the letter g entered into the search query.

Usar la propiedad "Where" de EntityDataSource para filtrar datos

Abra la página Students.aspx que creó en el tutorial anterior. Como se ha configurado actualmente, el control GridView de la página muestra todos los nombres del conjunto de entidades People. Sin embargo, solo quiere mostrar a los alumnos, que puede encontrar seleccionando Person entidades que tienen fechas de inscripción no nulas.

Cambie a vista Diseño y seleccione el control EntityDataSource. En la ventana Propiedades , establezca la propiedad Where en it.EnrollmentDate is not null.

Image01

La sintaxis que se usa en la propiedad Where del control EntityDataSource es Entity SQL. Entity SQL es similar a Transact-SQL, pero se personaliza para su uso con entidades en lugar de objetos de base de datos. En la expresión it.EnrollmentDate is not null, la palabra it representa una referencia a la entidad devuelta por la consulta. Por lo tanto, it.EnrollmentDate hace referencia a la propiedad EnrollmentDate de la entidad Person que devuelve el control EntityDataSource.

Ejecute la página. La lista de alumnos ahora solo contiene alumnos. (No se muestran filas donde no hay ninguna fecha de inscripción).

Screenshot of the Internet Explorer window, which shows the Student List view with a table of students.

Uso de la propiedad EntityDataSource "OrderBy" para ordenar datos

También desea que esta lista esté en orden de nombres cuando se muestre por primera vez. Con la página Students.aspx todavía abierta en vista Diseño y con el control EntityDataSource aún seleccionado, en la ventana Propiedades, establezca la propiedad OrderBy en it.LastName.

Image05

Ejecute la página. La lista de alumnos está ahora ordenada por apellidos.

Image04

Usar un parámetro de control para establecer la propiedad "Where"

Al igual que con otros controles de origen de datos, puede pasar valores de parámetro a la propiedad Where. En la página Courses.aspx que creó en la parte 2 del tutorial, puede usar este método para mostrar cursos asociados al departamento que un usuario selecciona en la lista desplegable.

Abra Courses.aspx y cambie a vista Diseño. Agregue un segundo control EntityDataSource a la página y nómbrelo CoursesEntityDataSource. Conéctelo al modelo de SchoolEntities y seleccione Courses como valor EntitySetName.

En la ventana Propiedades, haga clic en los puntos suspensivos del cuadro de propiedades Where. (Asegúrese de que el control CoursesEntityDataSource sigue seleccionado antes de utilizar la ventana Propiedades).

Image06

Aparecerá el cuadro de diálogo Editor de expresiones. En este cuadro de diálogo, seleccione Generar automáticamente la expresión Where en función de los parámetros proporcionados y luego haga clic en Agregar parámetro. Asigne un nombre al parámetro DepartmentID, seleccione Control como valor Origen del parámetro y seleccione DepartmentsDropDownList como valor de ControlID.

Image07

Haga clic en Mostrar propiedades avanzadas y, en la ventana Propiedades del cuadro de diálogo Editor de expresiones, cambie la propiedad Type a Int32.

Image15

Cuando haya terminado, haga clic en Aceptar.

Debajo de la lista desplegable, agregue un control GridView a la página y asígnele el nombre CoursesGridView. Conéctelo al control de origen de datos CoursesEntityDataSource, haga clic en Actualizar esquema, haga clic en Editar columnas y quite la columna DepartmentID. El marcado de control GridView es similar al siguiente ejemplo.

<asp:GridView ID="CoursesGridView" runat="server" AutoGenerateColumns="False" 
        DataKeyNames="CourseID" DataSourceID="CoursesEntityDataSource">
        <Columns>
            <asp:BoundField DataField="CourseID" HeaderText="ID" ReadOnly="True" 
                SortExpression="CourseID" />
            <asp:BoundField DataField="Title" HeaderText="Title" SortExpression="Title" />
            <asp:BoundField DataField="Credits" HeaderText="Credits" 
                SortExpression="Credits" />
        </Columns>
    </asp:GridView>

Cuando el usuario cambia el departamento seleccionado en la lista desplegable, quiere que la lista de cursos asociados cambie automáticamente. Para ello, seleccione la lista desplegable y, en la ventana Propiedades, establezca la propiedad AutoPostBack en True.

Image08

Ahora que ha terminado de utilizar el diseñador, cambie a la vista Origen y sustituya las propiedades ConnectionString y DefaultContainer del control CoursesEntityDataSource por el atributo ContextTypeName="ContosoUniversity.DAL.SchoolEntities". Cuando haya terminado, el marcado del control tendrá un aspecto similar al del siguiente ejemplo.

<asp:EntityDataSource ID="CoursesEntityDataSource" runat="server" 
        ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="false"
        EntitySetName="Courses" 
        AutoGenerateWhereClause="true" Where="">
        <WhereParameters>
            <asp:ControlParameter ControlID="DepartmentsDropDownList" Type="Int32" 
                Name="DepartmentID" PropertyName="SelectedValue" />
        </WhereParameters>
    </asp:EntityDataSource>

Ejecute la página y use la lista desplegable para seleccionar diferentes departamentos. Solo se muestran los cursos ofrecidos por el departamento seleccionado en el control GridView.

Image09

Uso de la propiedad "GroupBy" de EntityDataSource para agrupar datos

Supongamos que Contoso University quiere colocar algunas estadísticas de cuerpo de alumnos en su página Acerca de. En concreto, quiere mostrar un desglose de los números de alumnos por la fecha en que se inscribió.

Abra About.aspxy, en vista Origen, reemplace el contenido existente del control BodyContent por "Estadísticas del cuerpo del alumno" entre etiquetas h2:

<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <h2>Student Body Statistics</h2>
</asp:Content>

Después del encabezado, agregue un control EntityDataSource y asígnele el nombre StudentStatisticsEntityDataSource. Conéctelo a SchoolEntities, seleccione el conjunto de entidades People y no modifique la casilla Seleccionar del asistente. Establezca las siguientes propiedades en la ventana Propiedades:

  • Para filtrar solo los alumnos, establezca la propiedad Where en it.EnrollmentDate is not null.
  • Para agrupar los resultados por la fecha de inscripción, establezca la propiedad GroupBy en it.EnrollmentDate.
  • Para seleccionar la fecha de inscripción y el número de alumnos, establezca la propiedad Select en it.EnrollmentDate, Count(it.EnrollmentDate) AS NumberOfStudents.
  • Para ordenar los resultados por la fecha de inscripción, establezca la propiedad OrderBy en it.EnrollmentDate.

En la vista Origen, reemplace las propiedades de nombre ConnectionString y DefaultContainer por una propiedad ContextTypeName. El marcado de control EntityDataSource ahora es similar al siguiente ejemplo.

<asp:EntityDataSource ID="StudentStatisticsEntityDataSource" runat="server" 
        ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False" 
        EntitySetName="People"
        Select="it.EnrollmentDate, Count(it.EnrollmentDate) AS NumberOfStudents" 
        OrderBy="it.EnrollmentDate" GroupBy="it.EnrollmentDate"
        Where="it.EnrollmentDate is not null" >
    </asp:EntityDataSource>

La sintaxis de las propiedades de Select, GroupBy y Where es similar a Transact-SQL, excepto la palabra clave it que especifica la entidad actual.

Agregue el marcado siguiente para crear un control GridView para mostrar los datos.

<asp:GridView ID="StudentStatisticsGridView" runat="server" AutoGenerateColumns="False" 
        DataSourceID="StudentStatisticsEntityDataSource">
        <Columns>
            <asp:BoundField DataField="EnrollmentDate" DataFormatString="{0:d}" 
                HeaderText="Date of Enrollment" 
                ReadOnly="True" SortExpression="EnrollmentDate" />
            <asp:BoundField DataField="NumberOfStudents" HeaderText="Students" 
                ReadOnly="True" SortExpression="NumberOfStudents" />
        </Columns>
    </asp:GridView>

Ejecute la página para ver una lista que muestra el número de alumnos por fecha de inscripción.

Screenshot of the Internet Explorer window, which shows the Student Body Statistics view with a table of enrollment dates.

Usar el control QueryExtender para filtrar y ordenar

El control QueryExtender proporciona una manera de especificar el filtrado y la ordenación en el marcado. La sintaxis es independiente del sistema de administración de bases de datos (DBMS) que está usando. También es generalmente independiente de Entity Framework, con la excepción de que la sintaxis que se usa para las propiedades de navegación es única para Entity Framework.

En esta parte del tutorial, usará un control QueryExtender para filtrar y ordenar los datos, y uno de los campos order-by será una propiedad de navegación.

(Si prefiere usar código en lugar de marcado para ampliar las consultas generadas automáticamente por el control EntityDataSource, puede hacerlo controlando el evento QueryCreated. Así es como el control QueryExtender extiende también las consultas de control EntityDataSource).

Abra la página Courses.aspx y, debajo del marcado que agregó anteriormente, inserte el siguiente marcado para crear un encabezado, un cuadro de texto para escribir cadenas de búsqueda, un botón de búsqueda y un control EntityDataSource enlazado al conjunto de entidades de Courses.

<h2>Courses by Name</h2>
    Enter a course name 
    <asp:TextBox ID="SearchTextBox" runat="server"></asp:TextBox>
     <asp:Button ID="SearchButton" runat="server" Text="Search" />
    <br /><br />
    <asp:EntityDataSource ID="SearchEntityDataSource" runat="server" 
        ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False" 
        EntitySetName="Courses"  
        Include="Department" >
    </asp:EntityDataSource>

Observe que la propiedad Include del control EntityDataSource está establecida en Department. En la base de datos, la tabla Course no contiene el nombre del departamento; contiene una columna de clave externa DepartmentID. Si estaba consultando la base de datos directamente, para obtener el nombre del departamento junto con los datos del curso, tendría que combinar las tablas de Course y Department. Al establecer la propiedad Include en Department, especifique que Entity Framework debe realizar el trabajo de obtener la entidad Department relacionada cuando obtiene una entidad Course. A continuación, la entidad Department se almacena en la propiedad de navegación Department de la entidad Course. (De forma predeterminada, la clase SchoolEntities generada por el diseñador de modelos de datos recupera los datos relacionados cuando es necesario y ha enlazado el control de origen de datos a esa clase, por lo que no es necesario establecer la propiedad Include. Sin embargo, la configuración mejora el rendimiento de la página, ya que, de lo contrario, Entity Framework realizaría llamadas independientes a la base de datos para recuperar datos de las entidades de Course y para las entidades Department relacionadas).

Después del control EntityDataSource que acaba de crear, inserte el siguiente marcado para crear un control QueryExtender enlazado a ese control EntityDataSource.

<asp:QueryExtender ID="SearchQueryExtender" runat="server" 
        TargetControlID="SearchEntityDataSource" >
        <asp:SearchExpression SearchType="StartsWith" DataFields="Title">
            <asp:ControlParameter ControlID="SearchTextBox" />
        </asp:SearchExpression>
        <asp:OrderByExpression DataField="Department.Name" Direction="Ascending">
            <asp:ThenBy DataField="Title" Direction="Ascending" />            
        </asp:OrderByExpression>
    </asp:QueryExtender>

El elemento SearchExpression especifica que desea seleccionar cursos cuyos títulos coincidan con el valor especificado en el cuadro de texto. Solo se compararán tantos caracteres como se escriban en el cuadro de texto, ya que la propiedad SearchType especifica StartsWith.

El elemento OrderByExpression especifica que el conjunto de resultados se ordenará por título de curso dentro del nombre del departamento. Observe cómo se especifica el nombre del departamento: Department.Name. Dado que la asociación entre la entidad Course y la entidad Department es uno a uno, la propiedad de navegación Department contiene una entidad Department. (Si se tratara de una relación uno a muchos, la propiedad contendría una colección). Para obtener el nombre del departamento, debe especificar la propiedad Name de la entidad Department.

Por último, agregue un control GridView para mostrar la lista de cursos:

<asp:GridView ID="SearchGridView" runat="server" AutoGenerateColumns="False" 
        DataKeyNames="CourseID" DataSourceID="SearchEntityDataSource"  AllowPaging="true">
        <Columns>
            <asp:TemplateField HeaderText="Department">
                <ItemTemplate>
                    <asp:Label ID="Label2" runat="server" Text='<%# Eval("Department.Name") %>'></asp:Label>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:BoundField DataField="CourseID" HeaderText="ID"/>
            <asp:BoundField DataField="Title" HeaderText="Title" />
            <asp:BoundField DataField="Credits" HeaderText="Credits" />
        </Columns>
    </asp:GridView>

La primera columna es un campo de plantilla que muestra el nombre del departamento. La expresión de enlace de datos especifica Department.Name, tal como vio en el control QueryExtender.

Ejecute la página. La presentación inicial muestra una lista de todos los cursos en orden por departamento y, a continuación, por título del curso.

Screenshot of the Internet Explorer window, which shows the Courses by Department and Courses by Name views.

Escriba "m" y haga clic en Buscar para ver todos los cursos cuyos títulos comienzan por "m" (la búsqueda no distingue mayúsculas de minúsculas).

Image12

Uso del operador "Me gusta" para filtrar datos

Puede lograr un efecto similar al de QueryExtenderlos StartsWith tipos de búsqueda , Containsy EndsWith del control mediante un Like operador en la EntityDataSource propiedad del Where control. En esta parte del tutorial, verá cómo usar el operador Like para buscar un alumno por nombre.

Abra Students.aspx en la vista de Origen. Después del control GridView, agregue el siguiente marcado:

<h2>Find Students by Name</h2>
    Enter any part of the name
    <asp:TextBox ID="SearchTextBox" runat="server" AutoPostBack="true"></asp:TextBox>
     <asp:Button ID="SearchButton" runat="server" Text="Search" />
    <br />
    <br />
    <asp:EntityDataSource ID="SearchEntityDataSource" runat="server" 
        ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False" 
        EntitySetName="People"
        Where="it.EnrollmentDate is not null and (it.FirstMidName Like '%' + @StudentName + '%' or it.LastName Like '%' + @StudentName + '%')" >
        <WhereParameters>
            <asp:ControlParameter ControlID="SearchTextBox" Name="StudentName" PropertyName="Text" 
             Type="String" DefaultValue="%"/>
        </WhereParameters>
    </asp:EntityDataSource>
    <asp:GridView ID="SearchGridView" runat="server" AutoGenerateColumns="False" DataKeyNames="PersonID"
        DataSourceID="SearchEntityDataSource" AllowPaging="true">
        <Columns>
            <asp:TemplateField HeaderText="Name" SortExpression="LastName, FirstMidName">
                <ItemTemplate>
                    <asp:Label ID="LastNameFoundLabel" runat="server" Text='<%# Eval("LastName") %>'></asp:Label>, 
                    <asp:Label ID="FirstNameFoundLabel" runat="server" Text='<%# Eval("FirstMidName") %>'></asp:Label>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Enrollment Date" SortExpression="EnrollmentDate">
                <ItemTemplate>
                    <asp:Label ID="EnrollmentDateFoundLabel" runat="server" Text='<%# Eval("EnrollmentDate", "{0:d}") %>'></asp:Label>
                </ItemTemplate>
            </asp:TemplateField>
        </Columns>
    </asp:GridView>

Este marcado es similar al que ha visto anteriormente, excepto el valor de la propiedad Where. La segunda parte de la expresión Where define una búsqueda de subcadenas (LIKE %FirstMidName% or LIKE %LastName%) que busca tanto en el nombre como en el apellido lo que se introduzca en el cuadro de texto.

Ejecute la página. Inicialmente verá todos los alumnos porque el valor predeterminado del parámetro StudentName es "%".

Image13

Escriba la letra "g" en el cuadro de texto y haga clic en Buscar. Verá una lista de alumnos que tienen un "g" en el nombre o el apellido.

Screenshot of the Internet Explorer window, which shows the Find Students by Name view with the letter g entered into the search query.

Ahora ha mostrado, actualizado, filtrado, ordenado y agrupado datos de tablas individuales. En el siguiente tutorial, comenzará a trabajar con datos relacionados (escenarios de maestro y detalle).