Crear una capa de acceso a datos (C#)

por Scott Mitchell

Descargar PDF

En este tutorial comenzaremos desde el principio y creamos la capa de acceso a datos (DAL), mediante conjuntos de datos con tipo, para tener acceso a la información de una base de datos.

Introducción

Como desarrolladores web, nuestra vidas gira en torno al trabajo con datos. Creamos bases de datos para almacenar los datos, código para recuperarlos y modificarlos, y páginas web para recopilarlos y resumirlos. Este es el primer tutorial de una serie larga que explorará las técnicas para implementar estos patrones comunes en ASP.NET 2,0. Comenzaremos por crear una arquitectura de software compuesta por una capa de acceso a datos (dal) mediante conjuntos de datos con tipo, una capa de lógica de negocios (BLL) que aplica reglas de negocios personalizadas y un nivel de presentación compuesto por páginas de ASP.net que comparten un diseño de página común. Una vez que se ha creado este terreno de back-end, pasaremos a los informes, donde se muestra cómo mostrar, resumir, recopilar y validar los datos de una aplicación Web. Estos tutoriales están orientados a ser concisos y proporcionan instrucciones paso a paso con muchas capturas de pantalla para guiarle en el proceso visualmente. Cada tutorial está disponible en C# y Visual Basic versiones e incluye una descarga del código completo usado. (Este primer tutorial es bastante largo, pero el resto se presenta en fragmentos mucho más digestibles).

Para estos tutoriales, usaremos una versión Microsoft SQL Server 2005 Express Edition de la base de datos Northwind colocada en el directorio App_Data . Además del archivo de base de datos, la carpeta App_Data contiene también los scripts SQL para crear la base de datos, en caso de que desee usar una versión de base de datos diferente. Estos scripts también se pueden descargar directamente de Microsoft, si así lo prefiere. Si usa otra versión de SQL Server de la base de datos Northwind, deberá actualizar el valor NORTHWNDConnectionString en el archivo Web. config de la aplicación. La aplicación web se compiló con Visual Studio 2005 Professional Edition como un proyecto de sitio web basado en sistema de archivos. Sin embargo, todos los tutoriales funcionarán igual de bien con la versión gratuita de Visual Studio 2005, Visual Web Developer.

En este tutorial comenzaremos desde el principio y creamos la capa de acceso a datos (DAL), seguida de la creación de la capa de lógica de negocios (BLL) en el segundo tutorial y de cómo trabajar con el diseño y la navegación de páginas en el tercero. Los tutoriales después del tercero se basarán en la base establecida en los tres primeros. Tenemos mucho que cubrir en este primer tutorial, así que inicie Visual Studio y comencemos.

Paso 1: crear un proyecto web y conectarse a la base de datos

Antes de poder crear la capa de acceso a datos (DAL), primero es necesario crear un sitio web y configurar nuestra base de datos. Empiece por crear un nuevo sitio Web ASP.NET basado en el sistema de archivos. Para ello, vaya al menú Archivo y elija nuevo sitio web, mostrando el cuadro de diálogo nuevo sitio Web. Elija la plantilla de sitio web de ASP.NET, establezca la lista desplegable ubicación en sistema de archivos, elija una carpeta para colocar el sitio web y establezca el idioma C#en.

crear un nuevo sitio web basado en el sistema de archivos

Figura 1: crear un nuevo sitio web basado en el sistema de archivos (haga clic para ver la imagen de tamaño completo)

Se creará un nuevo sitio web con una página de ASP.NET . aspx predeterminada y una carpeta de datos de_ de la aplicación.

Una vez creado el sitio web, el siguiente paso es agregar una referencia a la base de datos en la Explorador de servidores de Visual Studio. Al agregar una base de datos al Explorador de servidores puede agregar tablas, procedimientos almacenados, vistas, etc. desde Visual Studio. También puede ver los datos de la tabla o crear sus propias consultas de forma manual o gráfica mediante el Generador de consultas. Además, cuando se crean los conjuntos de datos con tipo para la capa DAL, será necesario señalar Visual Studio en la base de datos desde la que se deben construir los conjuntos de datos con tipo. Aunque podemos proporcionar esta información de conexión en ese momento en el tiempo, Visual Studio rellena automáticamente una lista desplegable de las bases de datos ya registradas en el Explorador de servidores.

Los pasos para agregar la base de datos Northwind al Explorador de servidores dependen de si desea usar la base de datos de SQL Server 2005 Express Edition en la carpeta App_Data o si tiene una configuración de servidor de base de datos Microsoft SQL Server 2000 o 2005 que desea usar en su lugar.

Usar una base de datos en la carpeta app_Data

Si no tiene un servidor de base de datos SQL Server 2000 o 2005 con el que conectarse o simplemente desea evitar tener que agregar la base de datos a un servidor de base de datos, puede usar la versión de SQL Server 2005 Express Edition de la base de datos Northwind que se encuentra en la carpeta de la _aplicación del sitio web descargado (archivo northwnd. MDF).

Una base de datos colocada en la aplicación_carpeta Data se agrega automáticamente a la explorador de servidores. Suponiendo que SQL Server 2005 Express Edition instalado en el equipo, debería ver un nodo denominado archivo NORTHWND. MDF en el Explorador de servidores, que puede expandir y explorar sus tablas, vistas, procedimientos almacenados, etc. (vea la figura 2).

La carpeta de datos de la_de la aplicación también puede contener archivos . mdb de Microsoft Access, que, como sus homólogos SQL Server, se agregan automáticamente a la explorador de servidores. Si no desea usar ninguna de las opciones de SQL Server, siempre puede descargar una versión de Microsoft Access del archivo de base de datos Northwind y colocarla en el directorio App_Data . Sin embargo, tenga en cuenta que las bases de datos de Access no tienen tantas características como SQL Server y no están diseñadas para usarse en escenarios de sitios Web. Además, un par de los 35 tutoriales utilizará ciertas características de nivel de base de datos que no son compatibles con el acceso.

Conexión a la base de datos en un servidor de base de datos Microsoft SQL Server 2000 o 2005

Como alternativa, puede conectarse a una base de datos Northwind instalada en un servidor de base de datos. Si el servidor de base de datos todavía no tiene instalada la base de datos Northwind, primero debe agregarla al servidor de base de datos ejecutando el script de instalación incluido en la descarga de este tutorial o descargando la versión SQL Server 2000 de Northwind y el script de instalación directamente desde el sitio web de Microsoft.

Una vez instalada la base de datos, vaya al Explorador de servidores en Visual Studio, haga clic con el botón derecho en el nodo conexiones de datos y elija Agregar conexión. Si no ve el Explorador de servidores vaya a la vista/Explorador de servidores, o presione Ctrl + Alt + S. Se abrirá el cuadro de diálogo Agregar conexión, donde puede especificar el servidor al que se va a conectar, la información de autenticación y el nombre de la base de datos. Una vez que haya configurado correctamente la información de conexión de base de datos y haya hecho clic en el botón Aceptar, la base de datos se agregará como un nodo debajo del nodo conexiones de datos. Puede expandir el nodo de base de datos para explorar sus tablas, vistas, procedimientos almacenados, etc.

Agregar una conexión a la base de datos Northwind del servidor de bases de datos

Figura 2: agregar una conexión a la base de datos Northwind del servidor de bases de datos

Paso 2: creación de la capa de acceso a datos

Al trabajar con datos, una opción consiste en incrustar la lógica específica de los datos directamente en el nivel de presentación (en una aplicación Web, las páginas de ASP.NET componen el nivel de presentación). Esto puede adoptar la forma de escribir código ADO.NET en la parte del código de la página ASP.NET o usar el control SqlDataSource de la parte de marcado. En cualquier caso, este enfoque acopla estrechamente la lógica de acceso a datos con la capa de presentación. Sin embargo, el enfoque recomendado es separar la lógica de acceso a datos de la capa de presentación. Esta capa independiente se conoce como la capa de acceso a datos, DAL para abreviar y se implementa normalmente como un proyecto de biblioteca de clases independiente. Las ventajas de esta arquitectura en capas están bien documentadas (consulte la sección "Lecturas adicionales" al final de este tutorial para obtener información sobre estas ventajas) y es el enfoque que se va a seguir en esta serie.

Todo el código específico del origen de datos subyacente, como la creación de una conexión a la base de datos, la emisión de comandos Select, Insert, Updatey Delete , etc., debe encontrarse en la capa dal. El nivel de presentación no debe contener ninguna referencia a ese código de acceso a datos, sino que debe realizar llamadas a la capa DAL para todas las solicitudes de datos. Los niveles de acceso a datos suelen contener métodos para tener acceso a los datos de la base de datos subyacente. La base de datos Northwind, por ejemplo, tiene tablas de productos y categorías que registran los productos de venta y las categorías a las que pertenecen. En nuestro DAL, tendremos métodos como:

  • GetCategories (), que devolverá información sobre todas las categorías
  • GetProducts () , que devolverá información sobre todos los productos
  • GetProductsByCategoryID (CategoryID) , que devolverá todos los productos que pertenecen a una categoría especificada
  • GetProductByProductID (ProductID) , que devolverá información sobre un producto determinado.

Estos métodos, cuando se invocan, se conectan a la base de datos, emiten la consulta adecuada y devuelven los resultados. La forma en que se devuelven estos resultados es importante. Estos métodos podrían devolver simplemente un conjunto de datos o DataReader rellenado por la consulta de base de datos, pero idealmente estos resultados se deben devolver mediante objetos fuertemente tipados. Un objeto fuertemente tipado es aquél cuyo esquema se define de forma rígida en tiempo de compilación, mientras que el contrario, un objeto débilmente tipado, es aquél cuyo esquema no se conoce hasta el tiempo de ejecución.

Por ejemplo, DataReader y el conjunto de datos (de forma predeterminada) son objetos débilmente tipados, ya que su esquema está definido por las columnas devueltas por la consulta de base de datos utilizada para rellenarlos. Para tener acceso a una columna determinada desde un objeto DataTable con tipo flexible, es necesario usar una sintaxis como: DataTable. Rows [Índice] ["columnName"]. La escritura floja de la DataTable en este ejemplo se exhibe por el hecho de que necesitamos tener acceso al nombre de la columna mediante una cadena o un índice ordinal. Por otro lado, una DataTable fuertemente tipada tendrá cada una de sus columnas implementadas como propiedades, lo que dará lugar a un código similar al siguiente: DataTable. Rows [Índice]. columnName .

Para devolver objetos fuertemente tipados, los desarrolladores pueden crear sus propios objetos comerciales personalizados o utilizar conjuntos de DataSet con tipo. El desarrollador implementa un objeto comercial como una clase cuyas propiedades suelen reflejar las columnas de la tabla de base de datos subyacente que representa el objeto comercial. Un conjunto de datos con tipo es una clase que Visual Studio genera automáticamente en función de un esquema de base de datos y cuyos miembros están fuertemente tipados según este esquema. El propio conjunto de tipos se compone de clases que extienden las clases DataSet, DataTable y DataRow de ADO.NET. Además de las tablas de datos fuertemente tipadas, los conjuntos de datos con tipo también incluyen TableAdapters, que son clases con métodos para rellenar las DataTables del conjunto de datos y propagar las modificaciones de las tablas de datos de nuevo a la base de datos.

Note

Para obtener más información sobre las ventajas y desventajas del uso de conjuntos de datos con tipo frente a objetos empresariales personalizados, consulte diseño de componentes de capa de datos y transferencia de datos a través de niveles.

Usaremos conjuntos de valores fuertemente tipados para la arquitectura de estos tutoriales. En la figura 3 se muestra el flujo de trabajo entre los distintos niveles de una aplicación que usa conjuntos de valores con tipo.

todo el código de acceso a datos se relega a la capa DAL

Figura 3: el código de acceso a todos los datos se relega a la capa Dal (haga clic para ver la imagen de tamaño completo)

Crear un conjunto de DataSet con tipo y un adaptador de tabla

Para empezar a crear nuestro DAL, empezamos agregando un conjunto de un conjunto de tipos a nuestro proyecto. Para ello, haga clic con el botón secundario en el nodo del proyecto en el Explorador de soluciones y elija Agregar un nuevo elemento. Seleccione la opción conjunto de nombres de la lista de plantillas y asígnele el nombre Northwind. xsd.

elegir agregar un nuevo conjunto de nuevos al proyecto

Figura 4: elegir agregar un nuevo conjunto de información al proyecto (haga clic para ver la imagen de tamaño completo)

Después de hacer clic en agregar, cuando se le pida que agregue el conjunto de los conjuntos de aplicaciones a la carpeta de código del_ de la aplicación, elija sí. A continuación, se mostrará el diseñador del conjunto de objetos con tipo y se iniciará el Asistente para configuración de TableAdapter, lo que le permitirá agregar su primer TableAdapter al conjunto de tipos.

Un conjunto de datos con tipo actúa como una colección fuertemente tipada de datos; se compone de instancias de DataTable fuertemente tipadas, cada una de las cuales, a su vez, se compone de instancias de DataRow fuertemente tipadas. Vamos a crear un DataTable fuertemente tipado para cada una de las tablas de base de datos subyacentes con las que necesitamos trabajar en esta serie de tutoriales. Comencemos con la creación de un objeto DataTable para la tabla Products .

Tenga en cuenta que las tablas de datos fuertemente tipadas no incluyen información sobre cómo obtener acceso a los datos de la tabla de base de datos subyacente. Para recuperar los datos con el fin de rellenar la DataTable, usamos una clase TableAdapter, que funciona como la capa de acceso a datos. En el caso de la DataTable de nuestros productos , el TableAdapter contendrá los métodos GetProducts () , GetProductByCategoryID (CategoryID) y así sucesivamente que se invocarán desde la capa de presentación. El rol de DataTable es actuar como los objetos fuertemente tipados que se usan para pasar datos entre las capas.

El Asistente para configuración de TableAdapter comienza solicitando seleccionar la base de datos con la que trabajar. La lista desplegable muestra las bases de datos en el Explorador de servidores. Si no agregó la base de datos Northwind al Explorador de servidores, puede hacer clic en el botón nueva conexión en este momento para hacerlo.

elija la base de datos Northwind en la lista desplegable

Figura 5: elija la base de datos Northwind en la lista desplegable (haga clic para ver la imagen de tamaño completo)

Después de seleccionar la base de datos y hacer clic en siguiente, se le preguntará si desea guardar la cadena de conexión en el archivo Web. config . Al guardar la cadena de conexión, evitará que esté codificada de forma rígida en las clases de TableAdapter, lo que simplifica las cosas si la información de la cadena de conexión cambia en el futuro. Si opta por guardar la cadena de conexión en el archivo de configuración, se coloca en la sección <connectionstrings> , que se puede cifrar opcionalmente para mejorar la seguridad o modificarse más adelante a través de la nueva página de propiedades de ASP.net 2,0 dentro de la herramienta de administración de GUI de IIS, que es más idónea para los administradores.

guardar la cadena de conexión en Web. config

Figura 6: Guarde la cadena de conexión en Web. config (haga clic para ver la imagen de tamaño completo)

A continuación, es necesario definir el esquema para el primer objeto DataTable fuertemente tipado y proporcionar el primer método que el TableAdapter debe usar al rellenar el conjunto de DataSet fuertemente tipado. Estos dos pasos se realizan simultáneamente mediante la creación de una consulta que devuelve las columnas de la tabla que queremos reflejar en el DataTable. Al final del asistente, asignaremos un nombre de método a esta consulta. Una vez que se ha realizado, este método se puede invocar desde el nivel de presentación. El método ejecutará la consulta definida y rellenará una DataTable fuertemente tipada.

Para empezar a definir la consulta SQL, primero debemos indicar cómo deseamos que el TableAdapter emita la consulta. Podemos usar una instrucción SQL ad hoc, crear un nuevo procedimiento almacenado o usar un procedimiento almacenado existente. Para estos tutoriales, usaremos instrucciones SQL ad hoc. Consulte el artículo de Brian Noyes, creación de una capa de acceso a datos con el diseñador de DataSet de Visual Studio 2005 para obtener un ejemplo del uso de procedimientos almacenados.

consultar los datos mediante una instrucción SQL ad hoc

Figura 7: consulta de los datos mediante una instrucción SQL ad hoc (haga clic para ver la imagen de tamaño completo)

En este momento, podemos escribir la consulta SQL a mano. Al crear el primer método en el TableAdapter, normalmente desea que la consulta devuelva las columnas que deben expresarse en el DataTable correspondiente. Para ello, se crea una consulta que devuelve todas las columnas y todas las filas de la tabla Products :

escriba la consulta SQL en el cuadro de texto

Figura 8: escriba la consulta SQL en el cuadro de texto (haga clic para ver la imagen de tamaño completo)

Como alternativa, use el Generador de consultas y construya gráficamente la consulta, como se muestra en la figura 9.

crear la consulta gráficamente, a través del editor de consultas

Ilustración 9: crear la consulta gráficamente mediante el editor de consultas (haga clic para ver la imagen de tamaño completo)

Después de crear la consulta, pero antes de pasar a la siguiente pantalla, haga clic en el botón Opciones avanzadas. En los proyectos de sitio web, "generar instrucciones INSERT, Update y DELETE" es la única opción avanzada seleccionada de forma predeterminada. Si ejecuta este asistente desde una biblioteca de clases o un proyecto de Windows, la opción "usar simultaneidad optimista" también se seleccionará. Deje la opción "usar simultaneidad optimista" desactivada por ahora. Examinaremos la simultaneidad optimista en futuros tutoriales.

seleccionar solo la opción generar instrucciones INSERT, Update y DELETE

Figura 10: seleccione solo la opción generar instrucciones INSERT, Update y Delete (haga clic para ver la imagen a tamaño completo)

Después de comprobar las opciones avanzadas, haga clic en siguiente para pasar a la última pantalla. Aquí se le pedirá que seleccione los métodos que se van a agregar al TableAdapter. Hay dos patrones para rellenar los datos:

  • Rellenar un DataTable con este enfoque se crea un método que toma un DataTable como parámetro y lo rellena basándose en los resultados de la consulta. Por ejemplo, la clase ADO.NET DataAdapter implementa este patrón con el método Fill () .
  • Devolver un DataTable con este enfoque el método crea y rellena la DataTable automáticamente y la devuelve como el valor devuelto de los métodos.

Puede hacer que el TableAdapter implemente uno de estos patrones o ambos. También puede cambiar el nombre de los métodos que se proporcionan aquí. Vamos a dejar ambas casillas activadas, aunque solo usaremos el último patrón en estos tutoriales. Además, vamos a cambiar el nombre del método más genérico GetData a GetProducts.

Si está activada, la casilla final "GenerateDBDirectMethods" crea los métodos Insert () , Update () y Delete () para el TableAdapter. Si deja esta opción desactivada, todas las actualizaciones deberán realizarse a través del método Update () de TableAdapter, que toma el DataSet con tipo, un objeto DataTable, una sola DataRow o una matriz de DataRows. (Si ha desactivado la opción "generar instrucciones INSERT, Update y DELETE" de las propiedades avanzadas de la figura 9, la configuración de esta casilla no tendrá ningún efecto. Deje esta casilla activada.

cambiar el nombre del método de GetData a GetProducts

Figura 11: cambie el nombre del método de GetData a GetProducts (haga clic para ver la imagen de tamaño completo)

Para completar el asistente, haga clic en finalizar. Una vez que se cierre el asistente, se devolverá al diseñador de DataSet, que muestra el DataTable que acabamos de crear. Puede ver la lista de columnas de la DataTable Products (ProductID, ProductName, etc.), así como los métodos de ProductsTableAdapter (Fill () y GetProducts () ).

los productos DataTable y ProductsTableAdapter se han agregado al conjunto de DataSet con tipo

Figura 12: los productos DataTable y ProductsTableAdapter se han agregado al conjunto de información con tipo (haga clic para ver la imagen de tamaño completo)

En este punto, tenemos un conjunto de DataSet con tipo con una sola DataTable (Northwind. Products) y una clase DataAdapter fuertemente tipada (NorthwindTableAdapters. ProductsTableAdapter) con un método GetProducts () . Estos objetos se pueden usar para tener acceso a una lista de todos los productos desde código como:

NorthwindTableAdapters.ProductsTableAdapter productsAdapter =
    new NorthwindTableAdapters.ProductsTableAdapter();
Northwind.ProductsDataTable products;
products = productsAdapter.GetProducts();
foreach (Northwind.ProductsRow productRow in products)
    Response.Write("Product: " + productRow.ProductName + "<br />");

Este código no nos requirió escribir un bit de código específico de acceso a datos. No tuvimos que crear instancias de ninguna clase ADO.NET, por lo que no tenemos que hacer referencia a ninguna cadena de conexión, consulta SQL o procedimiento almacenado. En su lugar, el TableAdapter proporciona el código de acceso a datos de bajo nivel para nosotros.

Cada objeto que se usa en este ejemplo también es fuertemente tipado, lo que permite que Visual Studio proporcione IntelliSense y la comprobación de tipos en tiempo de compilación. Y lo mejor de todos los objetos DataTable devueltos por TableAdapter se pueden enlazar a controles Web de datos de ASP.NET, como GridView, DetailsView, DropDownList, CheckBoxList y otros muchos. En el ejemplo siguiente se muestra cómo enlazar la DataTable devuelta por el método GetProducts () a un control GridView en una sola exploraciones de tres líneas de código dentro de la Página_ controlador de eventos de carga.

AllProducts.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="AllProducts.aspx.cs"
    Inherits="AllProducts" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>View All Products in a GridView</title>
    <link href="Styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <h2>
            All Products</h2>
        <p>
            <asp:GridView ID="GridView1" runat="server"
             CssClass="DataWebControlStyle">
               <HeaderStyle CssClass="HeaderStyle" />
               <AlternatingRowStyle CssClass="AlternatingRowStyle" />
            </asp:GridView>
             </p>
    </div>
    </form>
</body>
</html>

AllProducts.aspx.cs

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using NorthwindTableAdapters;
public partial class AllProducts : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        ProductsTableAdapter productsAdapter = new
         ProductsTableAdapter();
        GridView1.DataSource = productsAdapter.GetProducts();
        GridView1.DataBind();
    }
}

la lista de productos se muestra en un control GridView

Figura 13: la lista de productos se muestra en un control GridView (haga clic para ver la imagen de tamaño completo)

Aunque en este ejemplo se requiere que se escriban tres líneas de código en la Página de la página de ASP.net_controlador de eventos de carga, veremos cómo usar ObjectDataSource para recuperar los datos de la capa Dal mediante declaración. Con ObjectDataSource no tendremos que escribir ningún código, sino que también tendrá compatibilidad con la paginación y la ordenación.

Paso 3: agregar métodos parametrizados a la capa de acceso a datos

En este momento, nuestra clase ProductsTableAdapter tiene un método, GetProducts () , que devuelve todos los productos de la base de datos. Aunque ser capaz de trabajar con todos los productos es definitivamente útil, hay ocasiones en las que queremos recuperar información acerca de un producto específico o de todos los productos que pertenecen a una categoría determinada. Para agregar esta funcionalidad a nuestra capa de acceso a datos, podemos agregar métodos parametrizados al TableAdapter.

Vamos a agregar el método GetProductsByCategoryID (CategoryID) . Para agregar un nuevo método a la capa DAL, vuelva al diseñador de DataSet, haga clic con el botón derecho en la sección ProductsTableAdapter y elija Agregar consulta.

Haga clic con el botón derecho en el TableAdapter y elija Agregar consulta.

Figura 14: haga clic con el botón derecho en el TableAdapter y elija Agregar consulta.

En primer lugar, se le preguntará si desea tener acceso a la base de datos mediante una instrucción SQL ad hoc o un procedimiento almacenado nuevo o existente. Vamos a elegir usar una instrucción SQL ad hoc de nuevo. A continuación, se le preguntará qué tipo de consulta SQL nos gustaría usar. Dado que queremos devolver todos los productos que pertenecen a una categoría especificada, queremos escribir una instrucción Select que devuelva filas.

optar por crear una instrucción SELECT que devuelve filas

Figura 15: elija crear una instrucción Select que devuelva filas (haga clic para ver la imagen de tamaño completo)

El siguiente paso consiste en definir la consulta SQL que se usa para tener acceso a los datos. Puesto que queremos devolver solo los productos que pertenecen a una categoría determinada, utilizo la misma instrucción Select de GetProducts (), pero agregamos la siguiente cláusula where : Where CategoryID = @CategoryID. El parámetro @CategoryID indica al asistente de TableAdapter que el método que se va a crear requerirá un parámetro de entrada del tipo correspondiente (es decir, un entero que acepta valores NULL).

especificar una consulta para devolver solo los productos de una categoría especificada

Figura 16: escriba una consulta para devolver solo los productos de la categoría especificada (haga clic para ver la imagen de tamaño completo)

En el paso final, podemos elegir los patrones de acceso a datos que se van a usar, así como personalizar los nombres de los métodos generados. Para el patrón de relleno, vamos a cambiar el nombre a FillByCategoryID y para el patrón de devolución de DataTable devuelto (los métodos GetX ), vamos a usar GetProductsByCategoryID.

elegir los nombres de los métodos de TableAdapter

Figura 17: elegir los nombres de los métodos de TableAdapter (haga clic para ver la imagen de tamaño completo)

Después de completar el asistente, el diseñador de DataSet incluye los nuevos métodos de TableAdapter.

Ahora se pueden consultar los productos por categoría.

Figura 18: ahora se pueden consultar los productos por categoría.

Dedique un momento a agregar un método GetProductByProductID (ProductID) con la misma técnica.

Estas consultas con parámetros se pueden probar directamente desde el diseñador de DataSet. Haga clic con el botón derecho en el método del TableAdapter y elija vista previa de los datos. A continuación, escriba los valores que se usarán para los parámetros y haga clic en vista previa.

se muestran los productos que pertenecen a la categoría bebidas

Figura 19: se muestran los productos que pertenecen a la categoría bebidas (haga clic para ver la imagen de tamaño completo)

Con el método GetProductsByCategoryID (CategoryID) de la capa Dal, ahora podemos crear una página ASP.net que muestra solo los productos de una categoría especificada. En el ejemplo siguiente se muestran todos los productos que se encuentran en la categoría Beverages, que tienen un CategoryID de 1.

Beverages.asp

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Beverages.aspx.cs"
    Inherits="Beverages" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
    <link href="Styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <h2>Beverages</h2>
        <p>
            <asp:GridView ID="GridView1" runat="server"
             CssClass="DataWebControlStyle">
               <HeaderStyle CssClass="HeaderStyle" />
               <AlternatingRowStyle CssClass="AlternatingRowStyle" />
            </asp:GridView>
             </p>
    </div>
    </form>
</body>
</html>

Beverages.aspx.cs

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using NorthwindTableAdapters;
public partial class Beverages : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        ProductsTableAdapter productsAdapter = new
         ProductsTableAdapter();
        GridView1.DataSource =
          productsAdapter.GetProductsByCategoryID(1);
        GridView1.DataBind();
    }
}

se muestran los productos de la categoría bebidas

Figura 20: se muestran los productos de la categoría bebidas (haga clic para ver la imagen de tamaño completo)

Paso 4: insertar, actualizar y eliminar datos

Hay dos patrones que se suelen usar para insertar, actualizar y eliminar datos. El primer patrón, que llamaré modelo directo de base de datos, implica la creación de métodos que, cuando se invocan, emiten un comando de inserción, actualizacióno eliminación a la base de datos que funciona en un solo registro de base de datos. Estos métodos normalmente se pasan en una serie de valores escalares (enteros, cadenas, valores booleanos, fechas y horas, etc.) que corresponden a los valores que se van a insertar, actualizar o eliminar. Por ejemplo, con este patrón para la tabla Products , el método Delete tomaría en un parámetro entero, lo que indicaba el ProductID del registro que se va a eliminar, mientras que el método Insert tomaría una cadena para el ProductName, un decimal para UnitPrice, un entero para UnitsOnStock, etc.

cada solicitud INSERT, Update y Delete se envía a la base de datos inmediatamente

Figura 21: cada solicitud INSERT, Update y Delete se envía a la base de datos inmediatamente (haga clic para ver la imagen de tamaño completo)

El otro patrón, al que haré referencia como el patrón de actualización por lotes, es actualizar todo un conjunto de filas, DataTable o colección de DataRows en una llamada al método. Con este patrón, un desarrollador elimina, inserta y modifica las filas de la fila de un DataTable y, a continuación, pasa esas filas o DataTable a un método Update. A continuación, este método enumera las filas de datos que se han pasado, determina si se han modificado, agregado o eliminado (a través del valor de la propiedad RowState de DataRow) y emite la solicitud de base de datos adecuada para cada registro.

todos los cambios se sincronizan con la base de datos cuando se invoca el método de actualización

Figura 22: todos los cambios se sincronizan con la base de datos cuando se invoca el método de actualización (haga clic para ver la imagen de tamaño completo)

El TableAdapter usa el patrón de actualización por lotes de forma predeterminada, pero también admite el patrón de DB Direct. Dado que se ha seleccionado la opción "generar instrucciones INSERT, Update y DELETE" desde las propiedades avanzadas al crear nuestro TableAdapter, ProductsTableAdapter contiene un método Update () , que implementa el patrón de actualización por lotes. En concreto, el TableAdapter contiene un método Update () al que se puede pasar el DataSet con tipo, un objeto DataTable fuertemente tipado, o una o varias filas de objetos. Si deja activada la casilla "GenerateDBDirectMethods" al crear primero el TableAdapter, el patrón de DB Direct también se implementará a través de los métodos Insert () , Update () y Delete () .

Ambos patrones de modificación de datos usan las propiedades InsertCommand, UpdateCommandy DeleteCommand del TableAdapter para emitir sus comandos Insert, Updatey Delete en la base de datos. Puede inspeccionar y modificar las propiedades InsertCommand, UpdateCommandy DeleteCommand ; para ello, haga clic en el TableAdapter en el diseñador de DataSet y, a continuación, vaya a la ventana Propiedades. (Asegúrese de que ha seleccionado el TableAdapter y de que el objeto ProductsTableAdapter es el seleccionado en la lista desplegable de la ventana Propiedades).

TableAdapter tiene propiedades InsertCommand, UpdateCommand y DeleteCommand

Figura 23: el TableAdapter tiene propiedades InsertCommand, UpdateCommandy DeleteCommand (haga clic para ver la imagen de tamaño completo)

Para examinar o modificar cualquiera de estas propiedades de comando de base de datos, haga clic en la subpropiedad CommandText , que abrirá la generador de consultas.

configurar las instrucciones INSERT, UPDATE y DELETE en el Generador de consultas

Figura 24: Configure las instrucciones Insert, UPDATEy Delete en el generador de consultas (haga clic para ver la imagen de tamaño completo)

En el ejemplo de código siguiente se muestra cómo usar el patrón de actualización por lotes para duplicar el precio de todos los productos que no se han suspendido y que tienen 25 unidades de existencias o menos.

NorthwindTableAdapters.ProductsTableAdapter productsAdapter =
  new NorthwindTableAdapters.ProductsTableAdapter();
// For each product, double its price if it is not discontinued and
// there are 25 items in stock or less
Northwind.ProductsDataTable products = productsAdapter.GetProducts();
foreach (Northwind.ProductsRow product in products)
   if (!product.Discontinued && product.UnitsInStock <= 25)
      product.UnitPrice *= 2;
// Update the products
productsAdapter.Update(products);

En el código siguiente se muestra cómo usar el patrón de base de datos Direct para eliminar mediante programación un determinado producto, actualizar uno y, a continuación, agregar uno nuevo:

NorthwindTableAdapters.ProductsTableAdapter productsAdapter =
    new NorthwindTableAdapters.ProductsTableAdapter();
// Delete the product with ProductID 3
productsAdapter.Delete(3);
// Update Chai (ProductID of 1), setting the UnitsOnOrder to 15
productsAdapter.Update("Chai", 1, 1, "10 boxes x 20 bags",
  18.0m, 39, 15, 10, false, 1);
// Add a new product
productsAdapter.Insert("New Product", 1, 1,
  "12 tins per carton", 14.95m, 15, 0, 10, false);

Crear métodos INSERT, Update y DELETE personalizados

Los métodos Insert () , Update () y Delete () creados por el método de DB Direct pueden ser un poco complicados, especialmente en el caso de las tablas con muchas columnas. En el ejemplo de código anterior, sin la ayuda de IntelliSense, no se borra especialmente la columna de la tabla Products que se asigna a cada parámetro de entrada a los métodos Update () e Insert () . Puede haber ocasiones en las que solo deseemos actualizar una o dos columnas, o que quiera un método Insert () personalizado que, quizás, devolverá el valor del campo de identidad (incremento automático) del registro que se acaba de insertar.

Para crear este tipo de método personalizado, vuelva al diseñador de DataSet. Haga clic con el botón secundario en el TableAdapter y elija Agregar consulta, y vuelva al asistente de TableAdapter. En la segunda pantalla se puede indicar el tipo de consulta que se va a crear. Vamos a crear un método que agrega un nuevo producto y, a continuación, devuelve el valor del ProductIDdel registro recién agregado. Por lo tanto, opte por crear una consulta Insert .

crear un método para agregar una nueva fila a la tabla Products

Figura 25: creación de un método para agregar una nueva fila a la tabla Products (haga clic para ver la imagen a tamaño completo)

En la pantalla siguiente aparece el CommandText de InsertCommand. Aumente esta consulta agregando Select SCOPE_Identity () al final de la consulta, que devolverá el último valor de identidad insertado en una columna de identidad en el mismo ámbito. (Consulte la documentación técnica para obtener más información acerca del ámbito_identidad () y por qué es probable que desee usar el ámbito_Identity () en lugar de @@IDENTITY). Asegúrese de finalizar la instrucción Insert con un punto y coma antes de agregar la instrucción Select .

aumentar la consulta para devolver el valor SCOPE_IDENTITY ()

Figura 26: aumentar la consulta para que devuelva el ámbito_ valor de identidad () (haga clic para ver la imagen de tamaño completo)

Por último, asigne al nuevo método el nombre InsertProduct.

establecer el nombre del nuevo método en InsertProduct

Figura 27: establecimiento del nuevo nombre de método en InsertProduct (haga clic para ver la imagen de tamaño completo)

Cuando vuelva al diseñador de DataSet verá que ProductsTableAdapter contiene un nuevo método, InsertProduct. Si este nuevo método no tiene un parámetro para cada columna de la tabla Products , lo más probable es que se haya olvidado de terminar la instrucción Insert con un punto y coma. Configure el método InsertProduct y asegúrese de que tiene un punto y coma delimitado por las instrucciones Insert y Select .

De forma predeterminada, los métodos Insert emiten métodos que no son de consulta, lo que significa que devuelven el número de filas afectadas. Sin embargo, queremos que el método InsertProduct devuelva el valor devuelto por la consulta, no el número de filas afectadas. Para ello, ajuste la propiedad ExecuteMode del método InsertProduct en escalar.

cambiar la propiedad ExecuteMode a escalar

Figura 28: cambie la propiedad ExecuteMode a escalar (haga clic para ver la imagen de tamaño completo)

En el código siguiente se muestra este nuevo método InsertProduct en acción:

NorthwindTableAdapters.ProductsTableAdapter productsAdapter =
    new NorthwindTableAdapters.ProductsTableAdapter();
// Add a new product
int new_productID = Convert.ToInt32(productsAdapter.InsertProduct
    ("New Product", 1, 1, "12 tins per carton", 14.95m, 10, 0, 10, false));
// On second thought, delete the product
productsAdapter.Delete(new_productID);

Paso 5: completar la capa de acceso a datos

Tenga en cuenta que la clase ProductsTableAdapters devuelve los valores CategoryID y SupplierID de la tabla Products , pero no incluye la columna CategoryName de la tabla Categories o la columna CompanyName de la tabla Suppliers , aunque es probable que se muestren las columnas que se van a mostrar al mostrar la información del producto. Podemos aumentar el método inicial del TableAdapter, GetProducts () , para incluir los valores de las columnas CategoryName y CompanyName , que actualizarán la DataTable fuertemente tipada para incluir también estas nuevas columnas.

Sin embargo, esto puede presentar un problema, ya que los métodos del TableAdapter para insertar, actualizar y eliminar datos se basan en este método inicial. Afortunadamente, los métodos generados automáticamente para insertar, actualizar y eliminar no se ven afectados por las subconsultas en la cláusula Select . Al tener cuidado de agregar nuestras consultas a categorías y proveedores como subconsultas, en lugar de unirse a, evitaremos tener que volver a trabajar con esos métodos para modificar los datos. Haga clic con el botón derecho en el método GetProducts () en ProductsTableAdapter y elija configurar. A continuación, ajuste la cláusula Select para que tenga el aspecto siguiente:

SELECT     ProductID, ProductName, SupplierID, CategoryID,
QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued,
(SELECT CategoryName FROM Categories
WHERE Categories.CategoryID = Products.CategoryID) as CategoryName,
(SELECT CompanyName FROM Suppliers
WHERE Suppliers.SupplierID = Products.SupplierID) as SupplierName
FROM         Products

actualizar la instrucción SELECT para el método GetProducts ()

Figura 29: actualización de la instrucción Select para el método GetProducts () (haga clic para ver la imagen de tamaño completo)

Después de actualizar el método GetProducts () para usar esta nueva consulta, el objeto DataTable incluirá dos nuevas columnas: CategoryName y NombreProveedor.

La DataTable Products tiene dos columnas nuevas

Figura 30: la DataTable Products tiene dos columnas nuevas

Dedique un momento a actualizar también la cláusula Select en el método GetProductsByCategoryID (CategoryID) .

Si actualiza la instrucción Select de GetProducts () mediante la sintaxis de join , el diseñador de DataSet no podrá generar automáticamente los métodos para insertar, actualizar y eliminar datos de la base de datos mediante el patrón de DB Direct. En su lugar, tendrá que crearlos manualmente de forma similar al método InsertProduct anteriormente en este tutorial. Además, tendrá que proporcionar manualmente los valores de las propiedades InsertCommand, UpdateCommandy DeleteCommand si desea utilizar el patrón de actualización por lotes.

Agregar los TableAdapters restantes

Hasta ahora, solo hemos examinado el trabajo con un solo TableAdapter para una tabla de base de datos única. Sin embargo, la base de datos Northwind contiene varias tablas relacionadas con las que se debe trabajar en nuestra aplicación Web. Un DataSet con tipo puede contener varias tablas de tipos de objeto. Por lo tanto, para completar el DAL, necesitamos agregar DataTables para las otras tablas que vamos a usar en estos tutoriales. Para agregar un nuevo TableAdapter a un conjunto de DataSet con tipo, abra el diseñador de DataSet, haga clic con el botón derecho en el diseñador y elija Agregar/TableAdapter. Esto creará un nuevo DataTable y TableAdapter y le guiará a través del asistente que hemos examinado anteriormente en este tutorial.

Dedique unos minutos a crear los siguientes TableAdapters y métodos con las siguientes consultas. Tenga en cuenta que las consultas de ProductsTableAdapter incluyen las subconsultas para captar los nombres de categoría y proveedor de cada producto. Además, si ha estado siguiendo, ya ha agregado los métodos GetProducts () y GetProductsByCategoryID (CategoryID) de la clase ProductsTableAdapter .

  • ProductsTableAdapter

    • GetProducts:

      SELECT     ProductID, ProductName, SupplierID, 
      CategoryID, QuantityPerUnit, UnitPrice, UnitsInStock, 
      UnitsOnOrder, ReorderLevel, Discontinued, 
      (SELECT CategoryName FROM Categories WHERE
      Categories.CategoryID = Products.CategoryID) as 
      CategoryName, (SELECT CompanyName FROM Suppliers
      WHERE Suppliers.SupplierID = Products.SupplierID) 
      as SupplierName
      FROM         Products
      
    • GetProductsByCategoryID:

      SELECT     ProductID, ProductName, SupplierID, CategoryID,
      QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
      ReorderLevel, Discontinued, (SELECT CategoryName
      FROM Categories WHERE Categories.CategoryID = 
      Products.CategoryID) as CategoryName,
      (SELECT CompanyName FROM Suppliers WHERE
      Suppliers.SupplierID = Products.SupplierID)
      as SupplierName
      FROM         Products
      WHERE      CategoryID = @CategoryID
      
    • GetProductsBySupplierID:

      SELECT     ProductID, ProductName, SupplierID, CategoryID,
      QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
      ReorderLevel, Discontinued, (SELECT CategoryName
      FROM Categories WHERE Categories.CategoryID = 
      Products.CategoryID) as CategoryName, 
      (SELECT CompanyName FROM Suppliers WHERE 
      Suppliers.SupplierID = Products.SupplierID) as SupplierName
      FROM         Products
      WHERE SupplierID = @SupplierID
      
    • GetProductByProductID:

      SELECT     ProductID, ProductName, SupplierID, CategoryID,
      QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
      ReorderLevel, Discontinued, (SELECT CategoryName 
      FROM Categories WHERE Categories.CategoryID = 
      Products.CategoryID) as CategoryName, 
      (SELECT CompanyName FROM Suppliers WHERE Suppliers.SupplierID = Products.SupplierID) 
      as SupplierName
      FROM         Products
      WHERE ProductID = @ProductID
      
  • CategoriesTableAdapter

    • GetCategories:

      SELECT     CategoryID, CategoryName, Description
      FROM         Categories
      
    • GetCategoryByCategoryID:

      SELECT     CategoryID, CategoryName, Description
      FROM         Categories
      WHERE CategoryID = @CategoryID
      
  • SuppliersTableAdapter

    • GetSuppliers:

      SELECT     SupplierID, CompanyName, Address,
      City, Country, Phone
      FROM         Suppliers
      
    • GetSuppliersByCountry:

      SELECT     SupplierID, CompanyName, Address,
      City, Country, Phone
      FROM         Suppliers
      WHERE Country = @Country
      
    • GetSupplierBySupplierID:

      SELECT     SupplierID, CompanyName, Address,
      City, Country, Phone
      FROM         Suppliers
      WHERE SupplierID = @SupplierID
      
  • EmployeesTableAdapter

    • GetEmployees:

      SELECT     EmployeeID, LastName, FirstName, Title,
      HireDate, ReportsTo, Country
      FROM         Employees
      
    • GetEmployeesByManager:

      SELECT     EmployeeID, LastName, FirstName, Title, 
      HireDate, ReportsTo, Country
      FROM         Employees
      WHERE ReportsTo = @ManagerID
      
    • GetEmployeeByEmployeeID:

      SELECT     EmployeeID, LastName, FirstName, Title,
      HireDate, ReportsTo, Country
      FROM         Employees
      WHERE EmployeeID = @EmployeeID
      

el diseñador de DataSet una vez agregados los cuatro TableAdapters

Figura 31: el diseñador de DataSet después de haber agregado los cuatro TableAdapters (haga clic para ver la imagen de tamaño completo)

Agregar código personalizado a la capa DAL

Los TableAdapters y DataTables que se agregan al conjunto de los tipos se expresan como un archivo de definición de esquemas XML (Northwind. xsd). Para ver esta información de esquema, haga clic con el botón secundario en el archivo Northwind. xsd en el explorador de soluciones y elija Ver código.

el archivo de definición de esquemas XML (XSD) para el DataSet con tipo de Northwind

Figura 32: el archivo de definición de esquemas XML (XSD) para el conjunto de información con tipo Northwind (haga clic para ver la imagen de tamaño completo)

Esta información de esquema se traduce C# en o Visual Basic código en tiempo de diseño cuando se compila o en tiempo de ejecución (si es necesario), momento en el que se puede recorrer paso a paso el depurador. Para ver este código generado automáticamente, vaya a la Vista de clases y explore en profundidad hasta las clases TableAdapter o DataSet con tipo. Si no ve el Vista de clases en la pantalla, vaya al menú Ver y selecciónelo desde allí, o presione Ctrl + Mayús + C. En el Vista de clases puede ver las propiedades, los métodos y los eventos de las clases DataSet y TableAdapter con tipo. Para ver el código de un método determinado, haga doble clic en el nombre del método en el Vista de clases o haga clic con el botón derecho en él y elija ir a definición.

Inspeccione el código generado automáticamente seleccionando ir a definición en el Vista de clases

Figura 33: Inspeccione el código generado automáticamente seleccionando ir a definición en el vista de clases

Aunque el código generado automáticamente puede ser un gran ahorro de tiempo, el código suele ser muy genérico y debe personalizarse para satisfacer las necesidades únicas de una aplicación. Sin embargo, el riesgo de extender el código generado automáticamente es que la herramienta que generó el código puede decidir que es el momento de "regenerar" y sobrescribir las personalizaciones. Con el nuevo concepto de clase parcial de .NET 2.0, es fácil dividir una clase en varios archivos. Esto nos permite agregar nuestros propios métodos, propiedades y eventos a las clases generadas automáticamente sin tener que preocuparse por la sobrescritura de Visual Studio de las personalizaciones.

Para mostrar cómo personalizar la capa DAL, vamos a agregar un método GetProducts () a la clase SuppliersRow . La clase SuppliersRow representa un único registro en la tabla Suppliers ; cada proveedor puede ser un proveedor de cero a muchos productos, por lo que GetProducts () devolverá los productos del proveedor especificado. Para ello, cree un nuevo archivo de clase en la carpeta de código del_ de la aplicación denominada SuppliersRow.CS y agregue el código siguiente:

using System;
using System.Data;
using NorthwindTableAdapters;
public partial class Northwind
{
    public partial class SuppliersRow
    {
        public Northwind.ProductsDataTable GetProducts()
        {
            ProductsTableAdapter productsAdapter =
             new ProductsTableAdapter();
            return
              productsAdapter.GetProductsBySupplierID(this.SupplierID);
        }
    }
}

Esta clase parcial indica al compilador que cuando se compila la clase Northwind. SuppliersRow para incluir el método GetProducts () que se acaba de definir. Si compila el proyecto y, a continuación, vuelve al Vista de clases verá que GetProducts () aparece ahora como un método de Northwind. SuppliersRow.

El método GetProducts () ahora forma parte de la clase Northwind. SuppliersRow

Figura 34: el método GetProducts () ahora forma parte de la clase Northwind. SuppliersRow

El método GetProducts () ahora se puede usar para enumerar el conjunto de productos para un proveedor determinado, como se muestra en el código siguiente:

NorthwindTableAdapters.SuppliersTableAdapter suppliersAdapter =
    new NorthwindTableAdapters.SuppliersTableAdapter();
// Get all of the suppliers
Northwind.SuppliersDataTable suppliers =
  suppliersAdapter.GetSuppliers();
// Enumerate the suppliers
foreach (Northwind.SuppliersRow supplier in suppliers)
{
    Response.Write("Supplier: " + supplier.CompanyName);
    Response.Write("<ul>");
    // List the products for this supplier
    Northwind.ProductsDataTable products = supplier.GetProducts();
    foreach (Northwind.ProductsRow product in products)
        Response.Write("<li>" + product.ProductName + "</li>");
    Response.Write("</ul><p> </p>");
}

Estos datos también se pueden mostrar en cualquiera de las páginas ASP. Controles Web de datos de la red. En la página siguiente se usa un control GridView con dos campos:

  • BoundField que muestra el nombre de cada proveedor y
  • TemplateField que contiene un control BulletedList que está enlazado a los resultados devueltos por el método GetProducts () para cada proveedor.

Examinaremos cómo mostrar estos informes maestros y detallados en futuros tutoriales. Por ahora, este ejemplo está diseñado para ilustrar el uso del método personalizado agregado a la clase Northwind. SuppliersRow .

SuppliersAndProducts.aspx

<%@ Page Language="C#" CodeFile="SuppliersAndProducts.aspx.cs"
    AutoEventWireup="true" Inherits="SuppliersAndProducts" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
    <link href="Styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <h2>
            Suppliers and Their Products</h2>
        <p>
            <asp:GridView ID="GridView1" runat="server"
             AutoGenerateColumns="False"
             CssClass="DataWebControlStyle">
                <HeaderStyle CssClass="HeaderStyle" />
                <AlternatingRowStyle CssClass="AlternatingRowStyle" />
                <Columns>
                    <asp:BoundField DataField="CompanyName"
                      HeaderText="Supplier" />
                    <asp:TemplateField HeaderText="Products">
                        <ItemTemplate>
                            <asp:BulletedList ID="BulletedList1"
                             runat="server" DataSource="<%# ((Northwind.SuppliersRow) ((System.Data.DataRowView) Container.DataItem).Row).GetProducts() %>"
                                 DataTextField="ProductName">
                            </asp:BulletedList>
                        </ItemTemplate>
                    </asp:TemplateField>
                </Columns>
            </asp:GridView>
             </p>
    </div>
    </form>
</body>
</html>

SuppliersAndProducts.aspx.cs

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using NorthwindTableAdapters;
public partial class SuppliersAndProducts : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        SuppliersTableAdapter suppliersAdapter = new
          SuppliersTableAdapter();
        GridView1.DataSource = suppliersAdapter.GetSuppliers();
        GridView1.DataBind();
    }
}

el nombre de la empresa del proveedor aparece en la columna izquierda, sus productos a la derecha

Figura 35: el nombre de la empresa del proveedor aparece en la columna izquierda, sus productos a la derecha (haga clic para ver la imagen a tamaño completo)

Resumen

Al crear una aplicación Web, la creación de la capa DAL debe ser uno de los primeros pasos que se produzca antes de empezar a crear el nivel de presentación. Con Visual Studio, la creación de una capa DAL basada en conjuntos de objetos con tipo es una tarea que se puede realizar en 10-15 minutos sin escribir una línea de código. Los tutoriales de avance se basarán en esta capa DAL. En el siguiente tutorial , vamos a definir un número de reglas de negocios y veremos cómo implementarlas en una capa de lógica de negocios independiente.

¡ Feliz programación!

Información adicional

Para obtener más información sobre los temas descritos en este tutorial, consulte los siguientes recursos:

Vídeo de aprendizaje sobre temas incluidos en este tutorial

Acerca del autor

Scott Mitchell, autor de siete libros de ASP/ASP. net y fundador de 4GuysFromRolla.com, ha estado trabajando con las tecnologías Web de Microsoft desde 1998. Scott funciona como consultor, profesor y redactor independiente. Su último libro se enseña a ASP.NET 2,0 en 24 horas. Puede ponerse en contacto con usted en mitchell@4GuysFromRolla.com. o a través de su blog, que encontrará en http://ScottOnWriting.NET.

Agradecimiento especial a

Muchos revisores útiles revisaron esta serie de tutoriales. Los revisores responsables de este tutorial son Ron Green, Hilton Giesenow, Dennis Patterson, Liz Shulok, Abel Gomez y Carlos Santos. ¿Está interesado en revisar los próximos artículos de MSDN? En caso afirmativo, suéltelo en mitchell@4GuysFromRolla.com.