Compartir a través de


Actualizar TableAdapter para usar JOIN (VB)

de Scott Mitchell

Descargar PDF

Al trabajar con una base de datos, es habitual solicitar datos que se distribuyen entre varias tablas. Para recuperar datos de dos tablas diferentes, podemos usar una subconsulta correlacionada o una operación JOIN. En este tutorial se comparan las subconsultas correlacionadas y la sintaxis JOIN antes de examinar cómo crear un TableAdapter que incluya una JOIN en su consulta principal.

Introducción

Con las bases de datos relacionales, los datos con los que estamos interesados en trabajar a menudo se distribuyen entre varias tablas. Por ejemplo, al mostrar información del producto, es probable que deseemos enumerar los nombres correspondientes de categoría y proveedor de cada producto. La Products tabla tiene CategoryID valores, y SupplierID, pero los nombres reales de categoría y proveedor se encuentran en la tabla Categories y la Suppliers, respectivamente.

Para recuperar información de otra tabla relacionada, podemos usar subconsultas correlacionadas o JOINs. Una subconsulta correlacionada es una consulta SELECT anidada que hace referencia a las columnas de la consulta externa. Por ejemplo, en el tutorial Creación de una capa de acceso a datos usamos dos subconsultas correlacionadas en la ProductsTableAdapter consulta principal para devolver los nombres de categoría y proveedor de cada producto. Es JOIN una construcción SQL que combina filas relacionadas de dos tablas diferentes. Usamos un elemento JOIN en el tutorial Consulta de datos con el control SqlDataSource para mostrar información de categorías junto con cada producto.

La razón por la que nos hemos abstenido de usar JOINs con los TableAdapters se debe a las limitaciones del asistente de TableAdapter para generar automáticamente las instrucciones correspondientes INSERT, UPDATE y DELETE. Más concretamente, si la consulta principal de TableAdapter contiene algún JOIN s, TableAdapter no puede crear automáticamente las instrucciones SQL ad hoc ni los procedimientos almacenados para sus InsertCommand, UpdateCommand, y DeleteCommand propiedades.

En este tutorial, compararemos brevemente y contrastamos las subconsultas correlacionadas y JOIN antes de explorar cómo crear un TableAdapter que incluya JOIN s en su consulta principal.

Comparación y contraste de subconsultas correlacionadas yJOIN s

Recuerde que el ProductsTableAdapter elemento creado en el primer tutorial de Northwind DataSet usa subconsultas correlacionadas para devolver la categoría y el nombre de proveedor correspondientes de cada producto. A continuación se muestra la ProductsTableAdapter consulta principal.

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

Las dos subconsultas correlacionadas, (SELECT CategoryName FROM Categories WHERE Categories.CategoryID = Products.CategoryID) y (SELECT CompanyName FROM Suppliers WHERE Suppliers.SupplierID = Products.SupplierID), son consultas que devuelven un único valor por producto como una columna adicional en la lista de columnas de la instrucción SELECT externa.

Como alternativa, se puede usar un JOIN para devolver el proveedor y el nombre de categoría de cada producto. La consulta siguiente devuelve la misma salida que la anterior, pero usa JOIN s en lugar de subconsultas:

SELECT ProductID, ProductName, Products.SupplierID, Products.CategoryID, 
       QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, 
       ReorderLevel, Discontinued,
       Categories.CategoryName, 
       Suppliers.CompanyName as SupplierName
FROM Products
    LEFT JOIN Categories ON
        Categories.CategoryID = Products.CategoryID
    LEFT JOIN Suppliers ON
        Suppliers.SupplierID = Products.SupplierID

Combina JOIN los registros de una tabla con registros de otra tabla en función de algunos criterios. En la consulta anterior, por ejemplo, indica LEFT JOIN Categories ON Categories.CategoryID = Products.CategoryID a SQL Server que combine cada registro de producto con el registro de categoría cuyo CategoryID valor coincida con el valor del CategoryID producto. El resultado combinado nos permite trabajar con los campos de categoría correspondientes para cada producto (como CategoryName).

Nota:

JOIN Se usan normalmente al consultar datos de bases de datos relacionales. Si no está familiarizado con la JOIN sintaxis o necesita refrescar un poco su uso, recomiendo el tutorial de uniones en SQL en W3 Schools. También merece la pena leer las JOIN secciones Fundamentos y Fundamentos de la subconsulta de los Libros en línea de SQL.

Dado que las subconsultas y las subconsultas correlacionadas se pueden usar para recuperar datos relacionados de otras tablas, muchos desarrolladores se quedan confundidos y se preguntan qué enfoque utilizar. Todos los gurús de SQL que he hablado han dicho aproximadamente lo mismo, que realmente no importa el rendimiento, ya que SQL Server producirá planes de ejecución aproximadamente idénticos. Su consejo, entonces, es usar la técnica con la que usted y su equipo están más cómodos. Merece la pena señalar que, tras impartir este consejo, estos expertos expresan inmediatamente su preferencia por JOIN frente a las subconsultas correlacionadas.

Al crear una capa de acceso a datos utilizando DataSets tipados, las herramientas funcionan mejor cuando se emplean subconsultas. En concreto, el asistente de TableAdapter no generará automáticamente las instrucciones correspondientes INSERT, UPDATE, y DELETE si la consulta principal contiene algún JOIN, pero generará automáticamente estas instrucciones cuando se usen subconsultas correlacionadas.

Para explorar esta deficiencia, cree un DataSet tipado temporal en la carpeta ~/App_Code/DAL. Durante el Asistente para configuración de TableAdapter, elija usar instrucciones SQL ad hoc y escriba la consulta siguiente SELECT (vea la figura 1):

SELECT ProductID, ProductName, Products.SupplierID, Products.CategoryID, 
       QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, 
       ReorderLevel, Discontinued,
       Categories.CategoryName, 
       Suppliers.CompanyName as SupplierName
FROM Products
    LEFT JOIN Categories ON
        Categories.CategoryID = Products.CategoryID
    LEFT JOIN Suppliers ON
        Suppliers.SupplierID = Products.SupplierID

Captura de pantalla que muestra la ventana del Asistente para configuración de TableAdaptor con una consulta especificada que contiene JOINs.

Figura 1: Escriba una consulta principal que contenga JOIN s (haga clic para ver la imagen de tamaño completo)

De forma predeterminada, TableAdapter creará automáticamente las instrucciones INSERT, UPDATE y DELETE basadas en la consulta principal. Si hace clic en el botón Avanzadas, puede ver que esta característica está habilitada. A pesar de esta configuración, TableAdapter no podrá crear las declaraciones INSERT, UPDATE y DELETE porque la consulta principal contiene un JOIN.

Captura de pantalla que muestra la ventana Opciones avanzadas con la casilla Generar instrucciones Insertar, Actualizar y Eliminar activadas.

Figura 2: Escribir una consulta principal que contiene JOIN s

Haga clic en Finalizar para completar el asistente. En este momento, el Diseñador de DataSets incluirá un solo TableAdapter con una DataTable que tiene columnas para cada uno de los campos devueltos en la lista de columnas de la SELECT consulta. Esto incluye el CategoryName y SupplierName, como muestra la figura 3.

DataTable incluye una columna para cada campo devuelto en la lista de columnas

Figura 3: DataTable incluye una columna para cada campo devuelto en la lista de columnas

Aunque DataTable tiene las columnas adecuadas, TableAdapter carece de valores para sus propiedades InsertCommand, UpdateCommand y DeleteCommand. Para confirmarlo, haga clic en TableAdapter en el Diseñador y, a continuación, vaya a la ventana Propiedades. Allí verá que las InsertCommand, UpdateCommand, y DeleteCommand propiedades se establecen en (Ninguno).

Las propiedades InsertCommand, UpdateCommand y DeleteCommand están establecidas en (None)

Figura 4: Las InsertCommandpropiedades , UpdateCommandy DeleteCommand se establecen en (Ninguno) (Haga clic para ver la imagen de tamaño completo)

Para solucionar este problema, podemos proporcionar manualmente las instrucciones SQL y los parámetros de las InsertCommandpropiedades , UpdateCommandy DeleteCommand a través de la ventana Propiedades. Como alternativa, podríamos empezar configurando la consulta principal de TableAdapter para que no incluya ninguna JOIN . Esto permitirá que las INSERT, UPDATE y DELETE declaraciones se generen automáticamente para nosotros. Después de completar el asistente, podríamos actualizar manualmente tableAdapter s SelectCommand desde la ventana Propiedades para que incluya la JOIN sintaxis.

Aunque este enfoque funciona, es muy frágil cuando se utilizan consultas SQL ad hoc porque cada vez que la consulta principal del TableAdapter se vuelve a configurar mediante el asistente, las instrucciones generadas automáticamente INSERT, UPDATE y DELETE se recrean. Esto significa que todas las personalizaciones realizadas más adelante se perderán si hacemos clic con el botón derecho en el TableAdapter, elegimos Configurar en el menú contextual y completemos de nuevo el asistente.

La frágilidad de las instrucciones generadas automáticamente por TableAdapter INSERT, UPDATE y DELETE es, afortunadamente, limitada a instrucciones SQL ad hoc. Si TableAdapter usa procedimientos almacenados, puede personalizar los SelectCommandprocedimientos almacenados , InsertCommand, UpdateCommando DeleteCommand y volver a ejecutar el Asistente para configuración de TableAdapter sin tener que temer que se modifiquen los procedimientos almacenados.

En los siguientes pasos crearemos un TableAdapter que, inicialmente, usa una consulta principal que omite cualquier JOIN s para que se generen automáticamente los procedimientos almacenados de inserción, actualización y eliminación correspondientes. A continuación, actualizaremos el SelectCommand para que utilice un JOIN que devuelva columnas adicionales de tablas relacionadas. Por último, crearemos una clase de capa lógica de negocios correspondiente y mostraremos el uso de TableAdapter en una página web de ASP.NET.

Paso 1: Crear el TableAdapter mediante una consulta principal simplificada

En este tutorial, agregaremos un objeto TableAdapter y un DataTable fuertemente tipado para la tabla Employees en el conjunto de datos NorthwindWithSprocs. La Employees tabla contiene un ReportsTo campo que especifica el EmployeeID del gerente del empleado. Por ejemplo, el empleado Anne Dodsworth tiene un ReportTo valor de 5, que es el EmployeeID de Steven Buchanan. Por lo tanto, Anne informa a Steven, su gerente. Junto con los informes sobre el valor de cada empleado ReportsTo, también podríamos querer recuperar el nombre de su gerente. Esto se puede lograr mediante JOIN. Pero el uso de un componente JOIN al crear inicialmente el TableAdapter impide que el asistente de configuración genere automáticamente las capacidades de inserción, actualización y eliminación correspondientes. Por lo tanto, empezaremos creando un TableAdapter cuya consulta principal no contiene ningún JOIN s. A continuación, en el paso 2, actualizaremos el procedimiento almacenado de consulta principal para recuperar el nombre del administrador a través de .JOIN

Para empezar, abra el conjunto de datos NorthwindWithSprocs en la carpeta ~/App_Code/DAL. Haga clic con el botón derecho en el Diseñador, seleccione la opción Agregar en el menú contextual y seleccione el elemento de menú TableAdapter. Se iniciará el Asistente para configuración de TableAdapter. Como se muestra en la figura 5, haga que el asistente cree nuevos procedimientos almacenados y haga clic en Siguiente. Para obtener un repaso sobre cómo crear nuevos procedimientos almacenados desde el asistente de TableAdapter, consulte el tutorial Creación de nuevos procedimientos almacenados para los TableAdapters de DataSet tipado.

Seleccione la opción Crear nuevos procedimientos almacenados.

Figura 5: Seleccionar la opción Crear nuevos procedimientos almacenados (Haga clic para ver la imagen de tamaño completo)

Use la siguiente SELECT instrucción para la consulta principal de TableAdapter:

SELECT EmployeeID, LastName, FirstName, Title, HireDate, ReportsTo, Country
FROM Employees

Dado que esta consulta no incluye ningún JOIN, el Asistente para TableAdapter creará automáticamente procedimientos almacenados con las declaraciones correspondientes INSERT, UPDATE, y DELETE, así como un procedimiento almacenado para ejecutar la consulta principal.

El siguiente paso nos permite asignar un nombre a los procedimientos almacenados de TableAdapter. Use los nombres Employees_Select, Employees_Insert, Employees_Updatey Employees_Delete, como se muestra en la figura 6.

Asigne un nombre a los procedimientos almacenados de TableAdapter.

Figura 6: Asignar un nombre a los procedimientos almacenados de TableAdapter (haga clic para ver la imagen de tamaño completo)

El paso final nos pide que asignemos un nombre a los métodos de TableAdapter. Use Fill y GetEmployees como nombres de método. Asegúrese también de dejar activada la casilla Crear métodos para enviar actualizaciones directamente a la base de datos (GenerateDBDirectMethods).

Asigne un nombre a los métodos Fill y GetEmployees de TableAdapter.

Figura 7: Asigne un nombre a los métodos Fill de TableAdapter y GetEmployees (haga clic para ver la imagen de tamaño completo)

Después de completar el asistente, tómese un momento para examinar los procedimientos almacenados en la base de datos. Debería ver cuatro nuevos: Employees_Select, Employees_Insert, Employees_Updatey Employees_Delete. A continuación, inspeccione los EmployeesDataTable y EmployeesTableAdapter que acaba de crear. DataTable contiene una columna para cada campo devuelto por la consulta principal. Haga clic en TableAdapter y, a continuación, vaya a la ventana Propiedades. Allí verá que las InsertCommandpropiedades , UpdateCommandy DeleteCommand están configuradas correctamente para llamar a los procedimientos almacenados correspondientes.

TableAdapter incluye funcionalidades de inserción, actualización y eliminación

Figura 8: TableAdapter incluye funcionalidades de inserción, actualización y eliminación (haga clic para ver la imagen de tamaño completo)

Con los procedimientos almacenados de inserción, actualización y eliminación creados automáticamente y las InsertCommand, UpdateCommand y DeleteCommand propiedades configuradas correctamente, estamos listos para personalizar el procedimiento almacenado SelectCommand para devolver información adicional sobre el gerente de cada empleado. En concreto, es necesario actualizar el procedimiento almacenado Employees_Select para usar un JOIN y devolver los valores FirstName y LastName del administrador. Una vez actualizado el procedimiento almacenado, es necesario actualizar DataTable para que incluya estas columnas adicionales. Abordaremos estas dos tareas en los pasos 2 y 3.

Paso 2: Personalizar el procedimiento almacenado para incluir unJOIN

Empiece por ir al Explorador de servidores, explorar en profundidad la carpeta Procedimientos almacenados de la base de datos Northwind y abrir el Employees_Select procedimiento almacenado. Si no ve este procedimiento almacenado, haga clic con el botón derecho en la carpeta Procedimientos almacenados y elija Actualizar. Actualice el procedimiento almacenado para que use LEFT JOIN para devolver el nombre completo del gerente.

SELECT Employees.EmployeeID, Employees.LastName, 
       Employees.FirstName, Employees.Title, 
       Employees.HireDate, Employees.ReportsTo, 
       Employees.Country,
       Manager.FirstName as ManagerFirstName, 
       Manager.LastName as ManagerLastName
FROM Employees
    LEFT JOIN Employees AS Manager ON
        Employees.ReportsTo = Manager.EmployeeID

Después de actualizar la SELECT instrucción, guarde los cambios en el menú Archivo y elija Guardar Employees_Select. Como alternativa, puede hacer clic en el icono Guardar de la barra de herramientas o presionar Ctrl+S. Después de guardar los cambios, haga clic con el botón derecho en el Employees_Select procedimiento almacenado en el Explorador de servidores y elija Ejecutar. Esto ejecutará el procedimiento almacenado y mostrará sus resultados en la ventana Salida (vea la figura 9).

Los resultados de los procedimientos almacenados se muestran en la ventana de salida.

Figura 9: Los resultados de los procedimientos almacenados se muestran en la ventana de salida (haga clic para ver la imagen de tamaño completo)

Paso 3: Actualizar las columnas de DataTable

En este momento, el Employees_Select procedimiento almacenado devuelve los valores ManagerFirstName y ManagerLastName, pero en EmployeesDataTable faltan estas columnas. Estas columnas que faltan se pueden agregar a DataTable de una de estas dos maneras:

  • Manualmente : haga clic con el botón derecho en DataTable en el Diseñador de conjuntos de datos y, en el menú Agregar, elija Columna. A continuación, puede asignar un nombre a la columna y establecer sus propiedades en consecuencia.
  • Automáticamente : el Asistente para configuración de TableAdapter actualizará las columnas de DataTable para reflejar los campos devueltos por el SelectCommand procedimiento almacenado. Al usar instrucciones SQL ad hoc, el asistente también quitará las propiedades InsertCommand, UpdateCommand y DeleteCommand ya que SelectCommand ahora contiene un JOIN. Pero al usar procedimientos almacenados, estas propiedades de comando permanecen intactas.

Hemos explorado la adición manual de columnas a DataTable en tutoriales anteriores, incluyendo Master/Detail Usando una Lista con Viñetas de Registros Maestros con un DataList de Detalles y Carga de Archivos, y examinaremos este proceso de nuevo con más detalle en nuestro siguiente tutorial. En este tutorial, sin embargo, vamos a usar el enfoque automático mediante el Asistente para configuración de TableAdapter.

Para empezar, haga clic con el botón derecho en el EmployeesTableAdapter y seleccione Configurar en el menú contextual. Esto abre el Asistente para configuración de TableAdapter, que enumera los procedimientos almacenados que se usan para seleccionar, insertar, actualizar y eliminar, junto con sus valores devueltos y parámetros (si los hay). En la figura 10 se muestra este asistente. Aquí podemos ver que el Employees_Select procedimiento almacenado ahora devuelve los ManagerFirstName campos y ManagerLastName .

El asistente muestra la lista de columnas actualizada para el procedimiento almacenado de Employees_Select

Figura 10: El asistente muestra la lista de columnas actualizada para el Employees_Select procedimiento almacenado (haga clic para ver la imagen de tamaño completo)

Para finalizar el asistente, haga clic en Instalar. Al volver al Diseñador de conjuntos de datos, EmployeesDataTable incluye dos columnas adicionales: ManagerFirstName y ManagerLastName.

EmployeesDataTable contiene dos columnas nuevas

Figura 11: Contiene EmployeesDataTable dos columnas nuevas (haga clic para ver la imagen de tamaño completo)

Para ilustrar que el procedimiento almacenado actualizado Employees_Select está en vigor y que las funcionalidades de inserción, actualización y eliminación de TableAdapter siguen siendo funcionales, vamos a crear una página web que permita a los usuarios ver y eliminar empleados. Sin embargo, antes de crear este tipo de página, primero necesitamos crear una nueva clase en la Capa de Lógica Empresarial para trabajar con empleados del NorthwindWithSprocs DataSet. En el paso 4, crearemos una EmployeesBLLWithSprocs clase. En el paso 5, usaremos esta clase desde una página de ASP.NET.

Paso 4: Implementar la capa lógica de negocios

Cree un nuevo archivo de clase en la ~/App_Code/BLL carpeta denominada EmployeesBLLWithSprocs.vb. Esta clase imita la semántica de la clase existente EmployeesBLL , solo esta nueva proporciona menos métodos y usa dataSet NorthwindWithSprocs (en lugar de Northwind DataSet). Agregue el siguiente código a la clase EmployeesBLLWithSprocs .

Imports NorthwindWithSprocsTableAdapters
<System.ComponentModel.DataObject()> _
Public Class EmployeesBLLWithSprocs
    Private _employeesAdapter As EmployeesTableAdapter = Nothing
    Protected ReadOnly Property Adapter() As EmployeesTableAdapter
        Get
            If _employeesAdapter Is Nothing Then
                _employeesAdapter = New EmployeesTableAdapter()
            End If
            Return _employeesAdapter
        End Get
    End Property
    <System.ComponentModel.DataObjectMethodAttribute _
        (System.ComponentModel.DataObjectMethodType.Select, True)> _
    Public Function GetEmployees() As NorthwindWithSprocs.EmployeesDataTable
        Return Adapter.GetEmployees()
    End Function
    <System.ComponentModel.DataObjectMethodAttribute _
        (System.ComponentModel.DataObjectMethodType.Delete, True)> _
    Public Function DeleteEmployee(ByVal employeeID As Integer) As Boolean
        Dim rowsAffected = Adapter.Delete(employeeID)
        'Return true if precisely one row was deleted, otherwise false
        Return rowsAffected = 1
    End Function
End Class

La EmployeesBLLWithSprocs propiedad de la clase s Adapter devuelve una instancia de DataSet NorthwindWithSprocs s EmployeesTableAdapter. Esto es utilizado por los métodos GetEmployees de la clase s DeleteEmployee. El método GetEmployees llama al método correspondiente EmployeesTableAdapter, que invoca el procedimiento almacenado GetEmployees y almacena sus resultados en un Employees_Select. El DeleteEmployee método llama de forma similar al EmployeesTableAdapter método s Delete , que invoca el Employees_Delete procedimiento almacenado.

Paso 5: Trabajar con los datos en la capa de presentación

Una vez completada la EmployeesBLLWithSprocs clase, estamos listos para trabajar con los datos de los empleados a través de una página de ASP.NET. Abra la página JOINs.aspx en la carpeta AdvancedDAL y arrastre un control GridView desde el cuadro de herramientas al Diseñador, estableciendo su propiedad ID en Employees. A continuación, desde la etiqueta inteligente GridView, enlace la cuadrícula a un nuevo control ObjectDataSource denominado EmployeesDataSource.

Configure ObjectDataSource para usar la clase EmployeesBLLWithSprocs y, en las pestañas SELECT y DELETE, asegúrese de que se seleccionen los métodos GetEmployees y DeleteEmployee en las listas desplegables. Haga clic en Finalizar para completar la configuración de ObjectDataSource.

Configurar objectDataSource para usar la clase EmployeesBLLWithSprocs

Figura 12: Configurar objectDataSource para usar la clase (EmployeesBLLWithSprocs la imagen de tamaño completo)

Hacer que ObjectDataSource use los métodos GetEmployees y DeleteEmployee

Figura 13: Hacer que ObjectDataSource use los GetEmployees métodos y DeleteEmployee (haga clic para ver la imagen de tamaño completo)

Visual Studio agregará un BoundField a GridView para cada una de las columnas de EmployeesDataTable. Quite todos estos BoundFields excepto Title, LastName, FirstName, ManagerFirstName y ManagerLastName, y cambie el nombre de las propiedades de los últimos cuatro BoundFields a Apellidos, Nombre, Nombre del Administrador y Apellidos del Administrador, respectivamente.

Para permitir que los usuarios eliminen empleados de esta página, es necesario hacer dos cosas. En primer lugar, indique a GridView que proporcione funcionalidades de eliminación comprobando la opción Habilitar eliminación de su etiqueta inteligente. En segundo lugar, cambie la propiedad del ObjectDataSource del valor del OldValuesParameterFormatString establecido por el asistente de ObjectDataSource (original_{0}) a su valor predeterminado ({0}). Después de realizar estos cambios, el marcado declarativo de GridView y ObjectDataSource deben ser similares a los siguientes:

<asp:GridView ID="Employees" runat="server" AutoGenerateColumns="False" 
    DataKeyNames="EmployeeID" DataSourceID="EmployeesDataSource">
    <Columns>
        <asp:CommandField ShowDeleteButton="True" />
        <asp:BoundField DataField="Title" 
            HeaderText="Title" 
            SortExpression="Title" />
        <asp:BoundField DataField="LastName" 
            HeaderText="Last Name" 
            SortExpression="LastName" />
        <asp:BoundField DataField="FirstName" 
            HeaderText="First Name" 
            SortExpression="FirstName" />
        <asp:BoundField DataField="ManagerFirstName" 
            HeaderText="Manager's First Name" 
            SortExpression="ManagerFirstName" />
        <asp:BoundField DataField="ManagerLastName" 
            HeaderText="Manager's Last Name" 
            SortExpression="ManagerLastName" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="EmployeesDataSource" runat="server" 
    DeleteMethod="DeleteEmployee" OldValuesParameterFormatString="{0}" 
    SelectMethod="GetEmployees" TypeName="EmployeesBLLWithSprocs">
    <DeleteParameters>
        <asp:Parameter Name="employeeID" Type="Int32" />
    </DeleteParameters>
</asp:ObjectDataSource>

Pruebe la página visitando a través de un explorador. Como se muestra en la figura 14, la página enumerará cada empleado y el nombre de su gerente (suponiendo que tenga uno).

El JOIN en el procedimiento almacenado Employees_Select devuelve el nombre del gerente.

Figura 14: en JOIN el Employees_Select procedimiento almacenado devuelve el nombre del administrador (haga clic para ver la imagen de tamaño completo)

Al hacer clic en el botón Eliminar, se inicia el flujo de trabajo de eliminación, que culmina en la ejecución del Employees_Delete procedimiento almacenado. Sin embargo, se produce un error en la instrucción intentada DELETE en el procedimiento almacenado debido a una violación de la restricción de clave externa (vea la Figura 15). En concreto, cada empleado tiene uno o varios registros en la Orders tabla, lo que provoca un error en la eliminación.

Eliminar a un empleado que tiene pedidos correspondientes resulta en una infracción de restricción de clave externa

Figura 15: Eliminar un empleado que tenga los pedidos correspondientes da como resultado una infracción de restricción de clave externa (haga clic para ver la imagen de tamaño completo)

Para permitir que un empleado se elimine, podría:

  • Actualizar la restricción de clave externa para que las eliminaciones sean en cascada.
  • Elimine manualmente los registros de la Orders tabla para los empleados que desea eliminar o
  • Actualice el Employees_Delete procedimiento almacenado para eliminar primero los registros relacionados de la Orders tabla antes de eliminar el Employees registro. Hemos discutido esta técnica en el tutorial Uso de procedimientos almacenados existentes para TableAdapters de DataSet con tipo.

Lo dejo como ejercicio para el lector.

Resumen

Al trabajar con bases de datos relacionales, es habitual que las consultas extraen sus datos de varias tablas relacionadas. Las subconsultas correlacionadas y JOIN s proporcionan dos técnicas diferentes para acceder a datos de tablas relacionadas en una consulta. En tutoriales anteriores, normalmente se usaban subconsultas correlacionadas porque TableAdapter no puede generar automáticamente INSERT, UPDATE y DELETE para consultas que involucran JOIN s. Aunque estos valores se pueden proporcionar manualmente, cuando se usen instrucciones SQL ad hoc, se sobrescribirá cualquier personalización cuando se complete el Asistente para configuración de TableAdapter.

Afortunadamente, TableAdapters creados mediante procedimientos almacenados no sufren la misma frágilidad que las creadas mediante instrucciones SQL ad hoc. Por lo tanto, es posible crear un TableAdapter cuya consulta principal use JOIN al emplear procedimientos almacenados. En este tutorial hemos visto cómo crear un tableAdapter de este tipo. Comenzamos utilizando una consulta JOIN-less SELECT para la consulta principal del TableAdapter, de modo que los procedimientos almacenados de inserción, actualización y eliminación correspondientes se crearan automáticamente. Con la configuración inicial de TableAdapter completada, aumentamos el procedimiento almacenado SelectCommand para utilizar un JOIN y volvimos a ejecutar el Asistente para Configuración de TableAdapter para actualizar las columnas EmployeesDataTable.

Al volver a ejecutar el Asistente para configuración de TableAdapter, se actualizaron automáticamente las EmployeesDataTable columnas para reflejar los campos de datos devueltos por el Employees_Select procedimiento almacenado. Como alternativa, podríamos haber agregado estas columnas manualmente a DataTable. Exploraremos la adición manual de columnas a DataTable en el siguiente tutorial.

¡Feliz programación!

Acerca del autor

Scott Mitchell, autor de siete libros de ASP/ASP.NET y fundador de 4GuysFromRolla.com, ha estado trabajando con tecnologías web de Microsoft desde 1998. Scott trabaja como consultor independiente, entrenador y escritor. Su último libro es Sams Teach Yourself ASP.NET 2.0 en 24 horas. Se puede contactar con él en mitchell@4GuysFromRolla.com.

Agradecimientos especiales a

Esta serie de tutoriales contó con la revisión de muchos revisores que fueron de gran ayuda. Los revisores principales de este tutorial fueron Hilton Geisenow, David Suru y Teresa Murphy. ¿Le interesa revisar mis próximos artículos de MSDN? Si es así, mándame un mensaje a mitchell@4GuysFromRolla.com.