Trabajar con columnas calculadas (C#)

por Scott Mitchell

Descargar PDF

Al crear una tabla de base de datos, Microsoft SQL Server permite definir una columna calculada cuyo valor se calcula a partir de una expresión que normalmente hace referencia a otros valores del mismo registro de base de datos. Estos valores son de solo lectura en la base de datos, lo que requiere consideraciones especiales al trabajar con TableAdapters. En este tutorial, aprenderá a superar los desafíos que plantean las columnas calculadas.

Introducción

Microsoft SQL Server permite columnas calculadas, que son columnas cuyos valores se calculan a partir de una expresión que normalmente hace referencia a los valores de otras columnas de la misma tabla. Por ejemplo, un modelo de datos de seguimiento de tiempo podría tener una tabla denominada ServiceLog con columnas como ServicePerformed, EmployeeID, Rate y Duration, entre otras. Aunque la cantidad debida por elemento de servicio (siendo la tasa multiplicada por la duración) se puede calcular a través de una página web u otra interfaz de programación, puede ser útil incluir una columna en la tabla ServiceLog denominada AmountDue que notifique esta información. Esta columna se podría crear como una columna normal, pero tendría que actualizarse en cualquier momento que cambien los valores de columna Rate o Duration. Un enfoque mejor sería convertir la columna AmountDue en una columna calculada mediante la expresión Rate * Duration. Si lo hace, SQL Server calculará automáticamente el valor de columna AmountDue cada vez que se haga referencia a él en una consulta.

Dado que un valor de columna calculada viene determinado por una expresión, estas columnas son de solo lectura y, por tanto, no pueden tener valores asignados a ellas en instrucciones INSERT o UPDATE. Sin embargo, cuando las columnas calculadas forman parte de la consulta principal de un TableAdapter que usa instrucciones SQL ad hoc, se incluyen automáticamente en las instrucciones INSERT y UPDATE generadas automáticamente. Por lo tanto, las propiedades InsertCommand y UpdateCommand y las consultas INSERT y UPDATE de TableAdapter deben actualizarse para quitar las referencias a las columnas calculadas.

Un desafío de usar columnas calculadas con un TableAdapter que usa instrucciones SQL ad hoc es que las consultas INSERT y UPDATE de TableAdapter se regeneran automáticamente en cualquier momento en que se complete el Asistente para configuración de TableAdapter. Por lo tanto, las columnas calculadas quitadas manualmente de las consultas INSERT y UPDATE volverán a aparecer si el asistente se vuelve a ejecutar. Aunque TableAdapters que usan procedimientos almacenados no sufren de este problema, tienen sus propias peculiaridades que abordaremos en el paso 3.

En este tutorial agregaremos una columna calculada a la tabla Suppliers de la base de datos Northwind y, a continuación, crearemos un TableAdapter correspondiente para trabajar con esta tabla y su columna calculada. Tendremos que hacer que TableAdapter use procedimientos almacenados en lugar de instrucciones SQL ad hoc para que nuestras personalizaciones no se pierdan cuando se use el Asistente para la configuración de TableAdapter.

¡Comencemos!

Paso 1: Agregar una columna calculada a la tabla Suppliers

La base de datos Northwind no tiene ninguna columna calculada, por lo que tendremos que agregar una. Para este tutorial, vamos a agregar una columna calculada a la tabla Suppliers denominada FullContactName que devuelve el nombre del contacto, el título y la empresa para la que trabajan con el siguiente formato: ContactName (ContactTitle, CompanyName). Esta columna calculada puede usarse en informes al mostrar información sobre proveedores.

Para empezar, abra la definición de tabla Suppliers haciendo clic con el botón derecho en la tabla Suppliers en el Explorador de servidores y seleccionando Abrir definición de tabla en el menú contextual. Esto mostrará las columnas de la tabla y sus propiedades, como su tipo de datos, si permiten NULL, etc. Para agregar una columna calculada, escriba el nombre de la columna en la definición de tabla. A continuación, escriba su expresión en el cuadro de texto (Fórmula) en la sección Especificación de columna calculada de la ventana Propiedades de columna (vea la Ilustración 1). Asigne un nombre a la columna calculada FullContactName y use la expresión siguiente:

ContactName + ' (' + CASE WHEN ContactTitle IS NOT NULL THEN 
    ContactTitle + ', ' ELSE '' END + CompanyName + ')'

Tenga en cuenta que las cadenas se pueden concatenar en SQL mediante el operador +. La instrucción CASE se puede usar como condicional en un lenguaje de programación tradicional. En la expresión anterior, la instrucción CASE se puede leer como: si ContactTitle no es NULL, se genera el valor ContactTitle concatenado con una coma; de lo contrario, no emite nada. Para obtener más información sobre la utilidad de la instrucción CASE, vea SQL CASE Instrucciones.

Nota:

En lugar de usar una instrucción CASE aquí, podríamos haber usado ISNULL(ContactTitle, '') como alternativa. ISNULL(checkExpression, replacementValue) devuelve checkExpression si no es NULL; de lo contrario, devuelve replacementValue. Aunque ISNULL o CASE funcionará en esta instancia, hay escenarios más complejos en los que la flexibilidad de la instrucción CASE no puede coincidir con ISNULL.

Después de agregar esta columna calculada, la pantalla debe ser similar a la captura de pantalla de la Ilustración 1.

Add a Computed Column Named FullContactName to the Suppliers Table

Ilustración 1: Agregar una columna calculada denominada FullContactName a la tabla Suppliers (haga clic para ver la imagen de tamaño completo)

Después de asignar un nombre a la columna calculada y escribir su expresión, guarde los cambios en la tabla haciendo clic en el icono Guardar de la barra de herramientas, presionando Ctrl+S o pasando al menú Archivo y seleccionando Guardar Suppliers.

Guardar la tabla debe actualizar el Explorador de servidores, incluida la columna recién agregada en la lista de columnas de la tabla Suppliers. Además, la expresión especificada en el cuadro de texto (Fórmula) se ajustará automáticamente a una expresión equivalente que tira espacios en blanco innecesarios, rodea los nombres de columna con corchetes ([]) e incluye paréntesis para mostrar explícitamente el orden de las operaciones:

(((([ContactName]+' (')+case when [ContactTitle] IS NOT NULL 
    then [ContactTitle]+', ' else '' end)+[CompanyName])+')')

Para obtener más información sobre las columnas calculadas en Microsoft SQL Server, consulte la documentación técnica. Consulte también el Tutorial: Especificar columnas calculadas para ver un tutorial paso a paso sobre la creación de columnas calculadas.

Nota:

De forma predeterminada, las columnas calculadas no se almacenan físicamente en la tabla, sino que se vuelven a calcular cada vez que se hace referencia a ellas en una consulta. Al activar la casilla Is Persisted, puede indicar a SQL Server que almacene físicamente la columna calculada en la tabla. Al hacerlo, se permite crear un índice en la columna calculada, lo que puede mejorar el rendimiento de las consultas que usan el valor de la columna calculada en sus cláusulas WHERE. Consulte Creación de índices en columnas calculadas para obtener más información.

Paso 2: Ver los valores de las columnas calculadas

Antes de empezar a trabajar en la capa de acceso a datos, vamos a dedicar un minuto a ver los valores FullContactName. En el Explorador de servidores, haga clic con el botón derecho en el nombre de la tabla Suppliers y elija Nueva consulta en el menú contextual. Se abrirá una ventana Consulta que nos pedirá que elija las tablas que se van a incluir en la consulta. Agregue la tabla Suppliers y haga clic en Cerrar. A continuación, compruebe las columnas CompanyName, ContactName, ContactTitle y FullContactName de la tabla Proveedores. Por último, haga clic en el icono de signo de exclamación rojo de la barra de herramientas para ejecutar la consulta y ver los resultados.

Como se muestra en la Ilustración 2, los resultados incluyen FullContactName, que enumera las columnas CompanyName, ContactNamey ContactTitle con el formato ldquo;ContactName (ContactTitle, CompanyName) .

The FullContactName Uses the Format ContactName (ContactTitle, CompanyName)

Ilustración 2: FullContactName usa el formato ContactName (ContactTitle, CompanyName) (Haga clic para ver la imagen de tamaño completo)

Paso 3: Agregar SuppliersTableAdapter al nivel de acceso a datos

Para trabajar con la información del proveedor en nuestra aplicación, primero necesitamos crear un TableAdapter y DataTable en nuestra DAL. Idealmente, esto se lograría con los mismos pasos sencillos examinados en tutoriales anteriores. Sin embargo, trabajar con columnas calculadas presenta algunas dificultades que merecen discusión.

Si usa un TableAdapter que usa instrucciones SQL ad hoc, simplemente puede incluir la columna calculada en la consulta principal de TableAdapter a través del Asistente para configuración de TableAdapter. Sin embargo, esto generará automáticamente las instrucciones INSERT y UPDATE que incluyen la columna calculada. Si intenta ejecutar uno de estos métodos, SqlException no se puede modificar un elemento con el mensaje ColumnName de columna porque es una columna calculada o es el resultado de un operador UNION. Aunque la instrucción INSERT y UPDATE se puede ajustar manualmente a través de las propiedades InsertCommand y UpdateCommand de TableAdapter, estas personalizaciones se perderán siempre que se vuelva a ejecutar el Asistente para la configuración de TableAdapter.

Debido a la fragilidad de TableAdapters que usan instrucciones SQL ad hoc, se recomienda usar procedimientos almacenados al trabajar con columnas calculadas. Si usa procedimientos almacenados existentes, basta con configurar TableAdapter como se describe en el tutorial Uso de procedimientos almacenados existentes para TableAdapters de DataSet con tipo. Sin embargo, si tiene el Asistente para TableAdapter, crea los procedimientos almacenados, pero es importante omitir inicialmente las columnas calculadas de la consulta principal. Si incluye una columna calculada en la consulta principal, el Asistente para configuración de TableAdapter le informará, al finalizar, de que no puede crear los procedimientos almacenados correspondientes. En resumen, es necesario configurar inicialmente TableAdapter mediante una consulta principal calculada sin columnas y, a continuación, actualizar manualmente el procedimiento almacenado correspondiente y el SelectCommand de TableAdapter para incluir la columna calculada. Este enfoque es similar al que se usa en el tutorial Actualización de TableAdapter para usar JOIN.

Para este tutorial, vamos a agregar un nuevo TableAdapter y hacer que cree automáticamente los procedimientos almacenados para nosotros. Por lo tanto, es necesario omitir inicialmente la columna calculada FullContactName de la consulta principal.

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 y, en el menú contextual, elija agregar un nuevo TableAdapter. Se iniciará el Asistente para configuración de TableAdapter. Especifique la base de datos en la que consultar datos (NORTHWNDConnectionString de Web.config) y haga clic en Siguiente. Puesto que aún no hemos creado ningún procedimiento almacenado para consultar o modificar la tabla Suppliers, seleccione la opción Crear nuevos procedimientos almacenados para que el asistente los cree y haga clic en Siguiente.

Choose the Create new stored procedures Option

Ilustración 3: Elegir la opción Crear nuevos procedimientos almacenados (haga clic para ver la imagen de tamaño completo)

El paso posterior nos solicita la consulta principal. Escriba la consulta siguiente, que devuelve las columnas SupplierID, CompanyName, ContactName y ContactTitle para cada proveedor. Tenga en cuenta que esta consulta omite intencionadamente la columna calculada (FullContactName); actualizaremos el procedimiento almacenado correspondiente para incluir esta columna en el paso 4.

SELECT SupplierID, CompanyName, ContactName, ContactTitle
FROM Suppliers

Después de escribir la consulta principal y hacer clic en Siguiente, el asistente nos permite asignar un nombre a los cuatro procedimientos almacenados que generará. Asigne a estos procedimientos almacenados el nombre Suppliers_Select, Suppliers_Insert, Suppliers_Update y Suppliers_Delete, como se muestra en la Ilustración 4.

Customize the Names of the Auto-Generated Stored Procedures

Ilustración 4: Personalizar los nombres de los procedimientos almacenados generados automáticamente (haga clic para ver la imagen de tamaño completo)

El siguiente paso del asistente nos permite asignar un nombre a los métodos de TableAdapter y especificar los patrones usados para acceder a los datos y actualizarlos. Deje activadas las tres casillas, pero cambie el nombre del método GetData a GetSuppliers. Haga clic en Finalizar para completar el asistente.

Rename the GetData Method to GetSuppliers

Ilustración 5: Cambiar el nombre del método GetData a GetSuppliers (haga clic para ver la imagen de tamaño completo)

Al hacer clic en Finalizar, el asistente creará los cuatro procedimientos almacenados y agregará TableAdapter y DataTable correspondientes al Conjunto de datos con tipo.

Paso 4: Incluir la columna calculada en la consulta principal de TableAdapter

Ahora es necesario actualizar TableAdapter y DataTable creados en el paso 3 para incluir la columna calculada FullContactName. Esto conlleva dos pasos:

  1. Actualizar el procedimiento almacenado Suppliers_Select para devolver la columna calculada FullContactName y
  2. Actualizar DataTable para incluir una columna FullContactName correspondiente.

Empiece por ir al Explorador de servidores y explorar en profundidad la carpeta Procedimientos almacenados. Abra el procedimiento almacenado Suppliers_Select y actualice la consulta SELECT para incluir la columna calculada FullContactName:

SELECT SupplierID, CompanyName, ContactName, ContactTitle, FullContactName
FROM Suppliers

Guarde los cambios en el procedimiento almacenado haciendo clic en el icono Guardar de la barra de herramientas, presionando Ctrl+S o seleccionando la opción Guardar Suppliers_Select en el menú Archivo.

A continuación, vuelva al Diseñador de conjuntos de datos, haga clic con el botón derecho en SuppliersTableAdapter y elija Configurar en el menú contextual. Tenga en cuenta que la columna Suppliers_Select ahora incluye la columna FullContactName en su colección Columnas de datos.

Run the TableAdapter s Configuration Wizard to Update the DataTable s Columns

Ilustración 6: Ejecutar el Asistente para configurar TableAdapter para actualizar las columnas de DataTable (haga clic para ver la imagen de tamaño completo)

Haga clic en Finalizar para completar el asistente. Esto agregará automáticamente una columna correspondiente a SuppliersDataTable. El Asistente para TableAdapter es lo suficientemente inteligente como para detectar que la columna FullContactName es una columna calculada y, por tanto, de solo lectura. Por lo tanto, establece la propiedad ReadOnly de la columna en true. Para comprobarlo, seleccione la columna de SuppliersDataTable y, a continuación, vaya a la ventana Propiedades (vea la Ilustración 7). Tenga en cuenta que las propiedades DataType y MaxLength de la columna FullContactName también se establecen en consecuencia.

The FullContactName Column is Marked as Read-Only

Ilustración 7: La columna FullContactName está marcada como de solo lectura (haga clic para ver la imagen de tamaño completo)

Paso 5: Agregar un método GetSupplierBySupplierID a TableAdapter

En este tutorial, crearemos una página de ASP.NET que muestre los proveedores en una cuadrícula actualizable. En los tutoriales anteriores, hemos actualizado un único registro de la capa de lógica de negocios recuperando ese registro concreto de la DAL como una DataTable fuertemente tipada, actualizando sus propiedades y, a continuación, enviando la DataTable actualizada de nuevo a la DAL para propagar los cambios a la base de datos. Para realizar este primer paso: recuperar el registro que se actualiza desde DAL, primero es necesario agregar un método GetSupplierBySupplierID(supplierID) a DAL.

Haga clic con el botón derecho en el SuppliersTableAdapter en el diseño del conjunto de datos y elija la opción Agregar consulta en el menú contextual. Como hicimos en el paso 3, deje que el asistente genere un nuevo procedimiento almacenado para nosotros seleccionando la opción Crear nuevo procedimiento almacenado (consulte la Ilustración 3 para ver una captura de pantalla de este paso del asistente). Dado que este método devolverá un registro con varias columnas, indique que queremos usar una consulta SQL que sea una SELECT que devuelva filas y haga clic en Siguiente.

Choose the SELECT which returns rows Option

Ilustración 8: Elegir la opción SELECT que devuelve filas (haga clic para ver la imagen de tamaño completo)

El paso posterior nos pide que la consulta se use para este método. Escriba lo siguiente, que devuelve los mismos campos de datos que la consulta principal, pero para un proveedor determinado.

SELECT SupplierID, CompanyName, ContactName, ContactTitle, FullContactName
FROM Suppliers
WHERE SupplierID = @SupplierID

La siguiente pantalla nos pide que asignemos un nombre al procedimiento almacenado que se generará automáticamente. Asigne un nombre a este procedimiento almacenado Suppliers_SelectBySupplierID y haga clic en Siguiente.

Name the Stored Procedure Suppliers_SelectBySupplierID

Ilustración 9: Nombre del procedimiento almacenado Suppliers_SelectBySupplierID (haga clic para ver la imagen de tamaño completo)

Por último, el asistente nos pide que los patrones de acceso a datos y los nombres de método se usen para TableAdapter. Deje activadas ambas casillas, pero cambie el nombre de los métodos FillBy y GetDataBy a FillBySupplierID y GetSupplierBySupplierID, respectivamente.

Name the TableAdapter Methods FillBySupplierID and GetSupplierBySupplierID

Ilustración 10: Asignar un nombre a los métodos FillBySupplierID y GetSupplierBySupplierID de TableAdapter (Haga clic para ver la imagen de tamaño completo)

Haga clic en Finalizar para completar el asistente.

Paso 6: Crear la capa de lógica de negocios

Antes de crear una página de ASP.NET que use la columna calculada creada en el paso 1, primero es necesario agregar los métodos correspondientes en el BLL. Nuestra página de ASP.NET, que crearemos en el paso 7, permitirá a los usuarios ver y editar proveedores. Por lo tanto, necesitamos nuestro BLL para proporcionar, como mínimo, un método para obtener todos los proveedores y otro para actualizar un proveedor determinado.

Cree un nuevo archivo de clase denominado SuppliersBLLWithSprocs en la carpeta ~/App_Code/BLL y agregue el código siguiente:

using System;
using System.Data;
using System.Configuration;
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 NorthwindWithSprocsTableAdapters;
[System.ComponentModel.DataObject]
public class SuppliersBLLWithSprocs
{
    private SuppliersTableAdapter _suppliersAdapter = null;
    protected SuppliersTableAdapter Adapter
    {
        get
        {
            if (_suppliersAdapter == null)
                _suppliersAdapter = new SuppliersTableAdapter();
            return _suppliersAdapter;
        }
    }
    [System.ComponentModel.DataObjectMethodAttribute
        (System.ComponentModel.DataObjectMethodType.Select, true)]
    public NorthwindWithSprocs.SuppliersDataTable GetSuppliers()
    {
        return Adapter.GetSuppliers();
    }
    [System.ComponentModel.DataObjectMethodAttribute
        (System.ComponentModel.DataObjectMethodType.Update, true)]
    public bool UpdateSupplier(string companyName, string contactName, 
        string contactTitle, int supplierID)
    {
        NorthwindWithSprocs.SuppliersDataTable suppliers = 
            Adapter.GetSupplierBySupplierID(supplierID);
        if (suppliers.Count == 0)
            // no matching record found, return false
            return false;
        NorthwindWithSprocs.SuppliersRow supplier = suppliers[0];
        supplier.CompanyName = companyName;
        if (contactName == null) 
            supplier.SetContactNameNull(); 
        else 
            supplier.ContactName = contactName;
        if (contactTitle == null) 
            supplier.SetContactTitleNull(); 
        else 
            supplier.ContactTitle = contactTitle;
        // Update the product record
        int rowsAffected = Adapter.Update(supplier);
        // Return true if precisely one row was updated, otherwise false
        return rowsAffected == 1;
    }
}

Al igual que las otras clases BLL, SuppliersBLLWithSprocs tiene una propiedad protectedAdapter que devuelve una instancia de la clase SuppliersTableAdapter junto con dos métodos public: GetSuppliers y UpdateSupplier. El método GetSuppliers llama y devuelve el SuppliersDataTable devuelto por el método GetSupplier correspondiente en la capa de acceso a datos. El método UpdateSupplier recupera información sobre el proveedor concreto que se actualiza a través de una llamada al método GetSupplierBySupplierID(supplierID) de DAL. A continuación, actualiza las propiedades CategoryName, ContactName y ContactTitle y confirma estos cambios en la base de datos llamando al método Update de capa de acceso a datos, pasando el objeto modificado SuppliersRow.

Nota:

Excepto para SupplierID y CompanyName, todas las columnas de la tabla Proveedores permiten valores NULL. Por lo tanto, si los parámetros contactName o contactTitle pasados son null, necesitamos establecer las propiedades ContactName y ContactTitle correspondientes en un valor de base de datos NULL mediante los métodos SetContactNameNull y SetContactTitleNull, respectivamente.

Paso 7: Trabajar con la columna calculada de la capa de presentación

Con la columna calculada agregada a la tabla Suppliers y DAL y BLL actualizadas en consecuencia, estamos listos para crear una página de ASP.NET que funcione con la columna calculada FullContactName. Para empezar, abra la página ComputedColumns.aspx en la carpeta AdvancedDAL y arrastre GridView desde el cuadro de herramientas al diseñador. Establezca la propiedad ID de GridView en Suppliers y, desde su etiqueta inteligente, vincule a un nuevo ObjectDataSource denominado SuppliersDataSource. Configure ObjectDataSource para usar la clase SuppliersBLLWithSprocs que hemos agregado en el paso 6 y haga clic en Siguiente.

Configure the ObjectDataSource to Use the SuppliersBLLWithSprocs Class

Ilustración 11: Configuración de ObjectDataSource para usar la clase SuppliersBLLWithSprocs (haga clic para ver la imagen de tamaño completo)

Solo hay dos métodos definidos en la clase SuppliersBLLWithSprocs: GetSuppliers y UpdateSupplier. Asegúrese de que estos dos métodos se especifican en las pestañas SELECT y UPDATE, respectivamente, y haga clic en Finalizar para completar la configuración de ObjectDataSource.

Tras finalizar el Asistente para configuración del origen de datos, Visual Studio agregará un BoundField para cada uno de los campos de datos devueltos. Quite el BoundField SupplierID y cambie las propiedades HeaderText de los BoundFields CompanyName, ContactName, ContactTitle y FullContactName a Company, Contact Name, Title y Full Contact Name, respectivamente. En la etiqueta inteligente, active la casilla Habilitar edición para activar las funcionalidades de edición integradas de GridView.

Además de agregar BoundFields a GridView, la finalización del Asistente para orígenes de datos también hace que Visual Studio establezca la propiedad OldValuesParameterFormatString de ObjectDataSource en original_{0}. Vuelva a revertir esta configuración a su valor predeterminado, {0}.

Después de realizar estas modificaciones en GridView y ObjectDataSource, su marcado declarativo debe ser similar al siguiente:

<asp:GridView ID="Suppliers" runat="server" AutoGenerateColumns="False" 
    DataKeyNames="SupplierID" DataSourceID="SuppliersDataSource">
    <Columns>
        <asp:CommandField ShowEditButton="True" />
        <asp:BoundField DataField="CompanyName" 
            HeaderText="Company" 
            SortExpression="CompanyName" />
        <asp:BoundField DataField="ContactName" 
            HeaderText="Contact Name" 
            SortExpression="ContactName" />
        <asp:BoundField DataField="ContactTitle" 
            HeaderText="Title" 
            SortExpression="ContactTitle" />
        <asp:BoundField DataField="FullContactName" 
            HeaderText="Full Contact Name"
            SortExpression="FullContactName" 
            ReadOnly="True" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="SuppliersDataSource" runat="server"
    SelectMethod="GetSuppliers" TypeName="SuppliersBLLWithSprocs" 
        UpdateMethod="UpdateSupplier">
    <UpdateParameters>
        <asp:Parameter Name="companyName" Type="String" />
        <asp:Parameter Name="contactName" Type="String" />
        <asp:Parameter Name="contactTitle" Type="String" />
        <asp:Parameter Name="supplierID" Type="Int32" />
    </UpdateParameters>
</asp:ObjectDataSource>

A continuación, visite esta página a través de un explorador. Como se muestra en la Ilustración 12, cada proveedor aparece en una cuadrícula que incluye la columna FullContactName, cuyo valor es simplemente la concatenación de las otras tres columnas con formato ContactName (ContactTitle, CompanyName).

Each Supplier is Listed in the Grid

Ilustración 12: Cada proveedor aparece en la cuadrícula (haga clic para ver la imagen de tamaño completo)

Al hacer clic en el botón Editar de un proveedor determinado, se produce un postback y se representa esa fila en su interfaz de edición (vea la Ilustración 13). Las tres primeras columnas se representan en su interfaz de edición predeterminada: un control TextBox cuya propiedad Text se establece en el valor del campo de datos. Sin embargo, la columna FullContactName permanece como texto. Cuando BoundFields se agregó a GridView al finalizar el Asistente para configuración del origen de datos, la propiedad ReadOnly del BoundField FullContactName se estableció en true porque la columna correspondiente FullContactName de SuppliersDataTable tiene su propiedad ReadOnly establecida en true. Como se indicó en el paso 4, la propiedad ReadOnly de FullContactName se estableció en true porque TableAdapter detectó que la columna era una columna calculada.

The FullContactName Column is Not Editable

Ilustración 13: La columna FullContactName no se puede editar (haga clic para ver la imagen de tamaño completo)

Continúe y actualice el valor de una o varias de las columnas editables y haga clic en Actualizar. Observe cómo el valor de FullContactName se actualiza automáticamente para reflejar el cambio.

Nota:

GridView usa actualmente BoundFields para los campos editables, lo que da lugar a la interfaz de edición predeterminada. Dado que el campo CompanyName es obligatorio, se debe convertir en un TemplateField que incluya RequiredFieldValidator. Lo dejo como un ejercicio para el lector interesado. Consulte el tutorial Adición de controles de validación a las interfaces de edición e inserción para obtener instrucciones paso a paso sobre cómo convertir un BoundField en un TemplateField y agregar controles de validación.

Resumen

Al definir el esquema de una tabla, Microsoft SQL Server permite la inclusión de columnas calculadas. Estas son columnas cuyos valores se calculan a partir de una expresión que normalmente hace referencia a los valores de otras columnas del mismo registro. Dado que los valores de las columnas calculadas se basan en una expresión, son de solo lectura y no se pueden asignar un valor en una instrucción INSERT o UPDATE. Esto presenta desafíos al usar una columna calculada en la consulta principal de un TableAdapter que intenta generar automáticamente las instrucciones INSERT, UPDATE y DELETE correspondientes.

En este tutorial se describen técnicas para superar los desafíos que plantean las columnas calculadas. En concreto, usamos procedimientos almacenados en TableAdapter para lidiar con la fragilidad inherente a TableAdapters que usan instrucciones SQL ad hoc. Al hacer que el Asistente para TableAdapter cree nuevos procedimientos almacenados, es importante que tengamos la consulta principal omitimos inicialmente las columnas calculadas porque su presencia impide que se generen los procedimientos almacenados de modificación de datos. Una vez configurado inicialmente el TableAdapter, su procedimiento almacenado SelectCommand se puede volver a crear para incluir las columnas calculadas.

¡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. Puede ponerse en contacto con él vía mitchell@4GuysFromRolla.com. o a través de su blog, que se puede encontrar en http://ScottOnWriting.NET.

Agradecimientos especiales a

Esta serie de tutoriales fue revisada por muchos revisores de gran ayuda. Los revisores principales de este tutorial fueron Hilton Geisenow y Teresa Murphy. ¿Le interesa revisar mis próximos artículos de MSDN? Si es así, escríbame a mitchell@4GuysFromRolla.com.