Creación de una aplicación de datos sencilla mediante ADO.NET

Nota:

Los conjuntos de datos y las clases relacionadas son tecnologías heredadas de .NET Framework de principios de la década de 2000 que permiten a las aplicaciones trabajar con datos en memoria mientras están desconectadas de la base de datos. Son especialmente útiles para las aplicaciones que permiten a los usuarios modificar los datos y conservar los cambios en la base de datos. Aunque los conjuntos de datos han demostrado ser una tecnología de gran éxito, se recomienda que las nuevas aplicaciones de .NET usen Entity Framework Core. Entity Framework proporciona una manera más natural de trabajar con datos tabulares como modelos de objetos y tiene una interfaz de programación más sencilla.

Al crear una aplicación que manipula datos en una base de datos, se realizan tareas básicas tales como definir cadenas de conexión, insertar datos y ejecutar procedimientos almacenados. Siguiendo este tema, puede detectar cómo interactuar con una base de datos dentro de una aplicación de "formularios sobre datos" de Windows Forms sencilla utilizando Visual C# o Visual Basic y ADO.NET. Todas las tecnologías de datos de .NET (incluidos los conjuntos de datos, LINQ to SQL y Entity Framework) en última instancia realizan pasos muy similares a los que se muestran en este artículo.

En este artículo se muestra una manera sencilla de extraer rápidamente los datos de una base de datos. Si la aplicación necesita modificar los datos de maneras no triviales y actualizar la base de datos, considere el uso de Entity Framework y del enlace de datos para sincronizar automáticamente los controles de la interfaz de usuario con los cambios en los datos subyacentes.

Importante

Para mantener el código sencillo, no se incluye el control de excepciones listo para producción.

Nota

Se puede acceder al código completo de este tutorial en el repositorio de GitHub de la documentación sobre Visual Studio en C# y Visual Basic.

Requisitos previos

Para crear la aplicación, necesitará:

  • Visual Studio con las cargas de trabajo de procesamiento y almacenamiento de datos y desarrollo de escritorio de .NET instaladas. Para instalarlas, abra el Instalador de Visual Studio y elija Modificar (o Más>modificar) junto a la versión de Visual Studio que desea modificar.

  • SQL Server Express LocalDB. Si no tiene SQL Server Express LocalDB, puede instalarlo desde la página de descarga de SQL Server.

En este tema se supone que está familiarizado con la funcionalidad básica del IDE de Visual Studio y puede crear una aplicación de Windows Forms, agregar formularios al proyecto, colocar botones y otros controles en los formularios, establecer las propiedades de los controles y codificar eventos simples. Si no está familiarizado con estas tareas, le recomendamos que complete el tutorial Creación de una aplicación de Windows Forms en Visual Studio con Visual Basic o Creación de una aplicación de Windows Forms en Visual Studio con C# antes de empezar este tutorial.

Configurar la base de datos de ejemplo

Siga estos pasos para crear la base de datos de ejemplo:

  1. En Visual Studio, abra la ventana Explorador de servidores.

  2. Haga clic con el botón derecho en Conexiones de datos y elija Crear nueva base de datos SQL Server.

  3. En el cuadro de texto Nombre del servidor, escriba (localdb)\mssqllocaldb.

  4. En el cuadro de texto Nombre de la base de datos nueva, escriba Sales y, después, elija Aceptar.

    Se creará la base de datos Sales vacía y se agregará al nodo Conexiones de datos en el Explorador de servidores.

  5. Haga clic con el botón derecho en la conexión de datos Sales y seleccione Nueva consulta.

    Se abre una ventana del editor de consultas.

  6. Copie el script de Transact-SQL de Sales en el Portapapeles.

  7. Pegue el script de T-SQL en el editor de consultas y, después, haga clic en el botón Ejecutar.

    Después de un breve tiempo, la consulta termina de ejecutarse y se crean los objeto de base de datos. La base de datos contiene dos tablas: Customer y Orders. Estas tablas no contienen datos inicialmente, pero puede agregarlos cuando ejecute la aplicación que va a crear. La base de datos también tiene cuatro procedimientos almacenados simples.

Crear los formularios y agregar controles

  1. Cree un proyecto de C# o Visual Basic con la plantilla de la Aplicación de Windows Forms (.NET Framework) y, a continuación, asígneles el nombre SimpleDataApp.

    Visual Studio crea el proyecto y varios archivos, incluido un formulario de Windows vacío denominado Form1.

  2. Agregue dos formularios de Windows al proyecto para que tenga tres formularios y, a continuación, asígneles los siguientes nombres:

    • Navegación

    • NewCustomer

    • FillOrCancel

  3. Para cada formulario, agregue los cuadros de texto, botones y otros controles que aparecen en las siguientes ilustraciones. Para cada control, establezca las propiedades que se describen en las tablas.

    Nota

    El cuadro de grupo y los controles de etiquetas agregan claridad pero no se utilizan en el código.

    Formulario Navigation

    Cuadro de diálogo de navegación

Controles del formulario Navigation Propiedades
Botón Nombre = btnGoToAdd
Botón Nombre = btnGoToFillOrCancel
Botón Nombre = btnExit

Formulario NewCustomer

Adición de un nuevo cliente y realización de un pedido

Controles del formulario NewCustomer Propiedades
TextBox Nombre = txtCustomerName
TextBox Nombre = txtCustomerID

De solo lectura = True
Botón Nombre = btnCreateAccount
NumericUpDown Posiciones decimales = 0

Máximo = 5000

Nombre = numOrderAmount
DateTimePicker Formato = Abreviado

Nombre = dtpOrderDate
Botón Nombre = btnPlaceOrder
Botón Nombre = btnAddAnotherAccount
Botón Nombre = btnAddFinish

Formulario FillOrCancel

rellenar o cancelar pedidos

Controles del formulario FillOrCancel Propiedades
TextBox Nombre = txtOrderID
Botón Nombre = btnFindByOrderID
DateTimePicker Formato = Abreviado

Nombre = dtpFillDate
DataGridView Nombre = dgvCustomerOrders

De solo lectura = True

Encabezados de filas visibles = False
Botón Nombre = btnCancelOrder
Botón Nombre = btnFillOrder
Botón Nombre = btnFinishUpdates

Almacenar la cadena de conexión

Cuando la aplicación intenta abrir una conexión a la base de datos, la aplicación debe tener acceso a la cadena de conexión. Para evitar escribir la cadena manualmente en cada formulario, almacene la cadena en el archivo App.config del proyecto y cree un método que devuelva la cadena cuando se llama al método desde cualquier formulario de la aplicación.

Para encontrar la cadena de conexión, haga clic con el botón derecho en la conexión de datos Sales en el Explorador de servidores y elija Propiedades. Busque la propiedad ConnectionString y pulse Ctrl+A, Ctrl+C para seleccionar y copiar la cadena en el Portapapeles.

  1. Si usa C#, en el Explorador de soluciones, expanda el nodo Propiedades del proyecto y abra el archivo Settings.settings. Si usa Visual Basic, en el Explorador de soluciones, haga clic en Mostrar todos los archivos, expanda el nodo Mi proyecto y abra el archivo Settings.settings.

  2. En la columna Nombre, escriba connString.

  3. En la lista Tipo, elija (Cadena de conexión).

  4. En la lista Ámbito, elija Aplicación.

  5. En la columna Valor, escriba la cadena de conexión (sin comillas externas) y después guarde los cambios.

    Captura de pantalla de la cadena de conexión en Settings.settings

Nota

En una aplicación real, debe almacenar la cadena de conexión de forma segura, como se describe en el artículo Cadenas de conexión y archivos de configuración.

Escribir el código para los formularios

Esta sección contiene información general sobre qué hace cada formulario. También proporciona el código que define la lógica subyacente cuando se hace clic en un botón del formulario.

El formulario Navigation se abre cuando se ejecuta la aplicación. El botón Agregar una cuenta abre el formulario NewCustomer. El botón Rellenar o cancelar órdenes abre el formulario FillOrCancel. El botón Salir cierra la aplicación.

Hacer que el formulario Navigation sea el formulario de inicio

Si usa C#, en el Explorador de soluciones, abra Program.cs y, a continuación, cambie la línea Application.Run a esta: Application.Run(new Navigation());

Si usa Visual Basic, en el Explorador de soluciones, abra la ventana Propiedades, elija la pestaña Aplicación y, después, elija SimpleDataApp.Navigation en la lista Formulario de inicio.

Creación de controladores de eventos generados automáticamente

Haga doble clic en los tres botones del formulario Navigation para crear métodos de controlador de eventos vacíos. Al hacer doble clic en los botones, también se agrega código generado automáticamente en el archivo de código del diseñador que permite hacer clic en un botón para generar un evento.

Nota:

Si omite la acción de doble clic en el diseñador y solo copia el código y lo pega en sus archivos de código, no olvide establecer el controlador de eventos en el método correcto. Puede hacerlo en la ventana Propiedades. Cambie a la pestaña Eventos (use el botón de la barra de herramientas con un icono de rayo) y busque el controlador Click.

Adición de código para la lógica del formulario Navigation

En la página de códigos del formulario Navegación, complete los cuerpos de método para los tres controladores de eventos generados con clic de botón, como se muestra en el código siguiente.

/// <summary>
/// Opens the NewCustomer form as a dialog box,
/// which returns focus to the calling form when it is closed. 
/// </summary>
private void btnGoToAdd_Click(object sender, EventArgs e)
{
    Form frm = new NewCustomer();
    frm.Show();
}

/// <summary>
/// Opens the FillorCancel form as a dialog box. 
/// </summary>
private void btnGoToFillOrCancel_Click(object sender, EventArgs e)
{
    Form frm = new FillOrCancel();
    frm.ShowDialog();
}

/// <summary>
/// Closes the application (not just the Navigation form).
/// </summary>
private void btnExit_Click(object sender, EventArgs e)
{
    this.Close();
}

Nota

El código de este tutorial está disponible en C# y Visual Basic. Para cambiar el lenguaje de código de esta página entre C# y Visual Basic, use el modificador de lenguaje de código de la parte superior de la página del lado derecho.

Formulario NewCustomer

Cuando escribe un nombre de cliente y después selecciona el botón Crear cuenta, el formulario NewCustomer crea una cuenta de cliente y SQL Server devuelve un valor IDENTITY como el nuevo número id. de cliente. A continuación, puede realizar un pedido para la nueva cuenta especificando una cantidad y una fecha de pedido, y seleccionando el botón Realizar pedido.

Creación de controladores de eventos generados automáticamente

Cree un controlador de eventos Click vacío para cada botón del formulario NewCustomer haciendo doble clic en cada uno de los cuatro botones. Al hacer doble clic en los botones, también se agrega código generado automáticamente en el archivo de código del diseñador que permite hacer clic en un botón para generar un evento.

Adición de código para la lógica del formulario NewCustomer

Para completar la lógica del formulario NewCustomer, siga estos pasos.

  1. Incluya el espacio de nombres System.Data.SqlClient en el ámbito para que no tenga que usar los nombres completos de sus miembros.

    using System.Data.SqlClient;
    
  2. Agregue algunas variables y métodos auxiliares a la clase como se muestra en el siguiente código.

    // Storage for IDENTITY values returned from database.
    private int parsedCustomerID;
    private int orderID;
    
    /// <summary>
    /// Verifies that the customer name text box is not empty.
    /// </summary>
    private bool IsCustomerNameValid()
    {
        if (txtCustomerName.Text == "")
        {
            MessageBox.Show("Please enter a name.");
            return false;
        }
        else
        {
            return true;
        }
    }
    
    /// <summary>
    /// Verifies that a customer ID and order amount have been provided.
    /// </summary>
    private bool IsOrderDataValid()
    {
        // Verify that CustomerID is present.
        if (txtCustomerID.Text == "")
        {
            MessageBox.Show("Please create customer account before placing order.");
            return false;
        }
        // Verify that Amount isn't 0.
        else if ((numOrderAmount.Value < 1))
        {
            MessageBox.Show("Please specify an order amount.");
            return false;
        }
        else
        {
            // Order can be submitted.
            return true;
        }
    }
    
    /// <summary>
    /// Clears the form data.
    /// </summary>
    private void ClearForm()
    {
        txtCustomerName.Clear();
        txtCustomerID.Clear();
        dtpOrderDate.Value = DateTime.Now;
        numOrderAmount.Value = 0;
        this.parsedCustomerID = 0;
    }
    
  3. Complete los cuerpos de método para los cuatro controladores de eventos generados con clic de botón, como se muestra en el código siguiente.

    /// <summary>
    /// Creates a new customer by calling the Sales.uspNewCustomer stored procedure.
    /// </summary>
    private void btnCreateAccount_Click(object sender, EventArgs e)
    {
        if (IsCustomerNameValid())
        {
            // Create the connection.
            using (SqlConnection connection = new SqlConnection(Properties.Settings.Default.connString))
            {
                // Create a SqlCommand, and identify it as a stored procedure.
                using (SqlCommand sqlCommand = new SqlCommand("Sales.uspNewCustomer", connection))
                {
                    sqlCommand.CommandType = CommandType.StoredProcedure;
    
                    // Add input parameter for the stored procedure and specify what to use as its value.
                    sqlCommand.Parameters.Add(new SqlParameter("@CustomerName", SqlDbType.NVarChar, 40));
                    sqlCommand.Parameters["@CustomerName"].Value = txtCustomerName.Text;
    
                    // Add the output parameter.
                    sqlCommand.Parameters.Add(new SqlParameter("@CustomerID", SqlDbType.Int));
                    sqlCommand.Parameters["@CustomerID"].Direction = ParameterDirection.Output;
    
                    try
                    {
                        connection.Open();
    
                        // Run the stored procedure.
                        sqlCommand.ExecuteNonQuery();
    
                        // Customer ID is an IDENTITY value from the database.
                        this.parsedCustomerID = (int)sqlCommand.Parameters["@CustomerID"].Value;
    
                        // Put the Customer ID value into the read-only text box.
                        this.txtCustomerID.Text = Convert.ToString(parsedCustomerID);
                    }
                    catch
                    {
                        MessageBox.Show("Customer ID was not returned. Account could not be created.");
                    }
                    finally
                    {
                        connection.Close();
                    }
                }
            }
        }
    }
    
    /// <summary>
    /// Calls the Sales.uspPlaceNewOrder stored procedure to place an order.
    /// </summary>
    private void btnPlaceOrder_Click(object sender, EventArgs e)
    {
        // Ensure the required input is present.
        if (IsOrderDataValid())
        {
            // Create the connection.
            using (SqlConnection connection = new SqlConnection(Properties.Settings.Default.connString))
            {
                // Create SqlCommand and identify it as a stored procedure.
                using (SqlCommand sqlCommand = new SqlCommand("Sales.uspPlaceNewOrder", connection))
                {
                    sqlCommand.CommandType = CommandType.StoredProcedure;
    
                    // Add the @CustomerID input parameter, which was obtained from uspNewCustomer.
                    sqlCommand.Parameters.Add(new SqlParameter("@CustomerID", SqlDbType.Int));
                    sqlCommand.Parameters["@CustomerID"].Value = this.parsedCustomerID;
    
                    // Add the @OrderDate input parameter.
                    sqlCommand.Parameters.Add(new SqlParameter("@OrderDate", SqlDbType.DateTime, 8));
                    sqlCommand.Parameters["@OrderDate"].Value = dtpOrderDate.Value;
    
                    // Add the @Amount order amount input parameter.
                    sqlCommand.Parameters.Add(new SqlParameter("@Amount", SqlDbType.Int));
                    sqlCommand.Parameters["@Amount"].Value = numOrderAmount.Value;
    
                    // Add the @Status order status input parameter.
                    // For a new order, the status is always O (open).
                    sqlCommand.Parameters.Add(new SqlParameter("@Status", SqlDbType.Char, 1));
                    sqlCommand.Parameters["@Status"].Value = "O";
    
                    // Add the return value for the stored procedure, which is  the order ID.
                    sqlCommand.Parameters.Add(new SqlParameter("@RC", SqlDbType.Int));
                    sqlCommand.Parameters["@RC"].Direction = ParameterDirection.ReturnValue;
    
                    try
                    {
                        //Open connection.
                        connection.Open();
    
                        // Run the stored procedure.
                        sqlCommand.ExecuteNonQuery();
    
                        // Display the order number.
                        this.orderID = (int)sqlCommand.Parameters["@RC"].Value;
                        MessageBox.Show("Order number " + this.orderID + " has been submitted.");
                    }
                    catch
                    {
                        MessageBox.Show("Order could not be placed.");
                    }
                    finally
                    {
                        connection.Close();
                    }
                }
            }
        }
    }
    
    /// <summary>
    /// Clears the form data so another new account can be created.
    /// </summary>
    private void btnAddAnotherAccount_Click(object sender, EventArgs e)
    {
        this.ClearForm();
    }
    
    /// <summary>
    /// Closes the form/dialog box.
    /// </summary>
    private void btnAddFinish_Click(object sender, EventArgs e)
    {
        this.Close();
    }
    

Formulario FillOrCancel

El formulario FillOrCancel ejecuta una consulta que devuelve un pedido cuando escribe un identificador de pedido y hace clic en el botón Find Order (Buscar pedido). La fila devuelta aparece en una cuadrícula de datos de solo lectura. Puede marcar el pedido como cancelado (X) si selecciona el botón Cancel order (Cancelar pedido) o puede marcar el pedido como rellenado (F) si selecciona el botón Fill Order (Rellenar pedido). Si selecciona de nuevo el botón Find Order (Buscar pedido), se mostrará la fila actualizada.

Creación de controladores de eventos generados automáticamente

Cree controladores de eventos Click vacíos para los cuatro botones del formulario FillOrCancel haciendo doble clic en los botones. Al hacer doble clic en los botones, también se agrega código generado automáticamente en el archivo de código del diseñador que permite hacer clic en un botón para generar un evento.

Adición de código para la lógica del formulario FillOrCancel

Para completar la lógica del formulario FillOrCancel, siga estos pasos.

  1. Incluya los dos espacios de nombres siguientes en el ámbito para que no tenga que usar los nombres completos de sus miembros.

    using System.Data.SqlClient;
    using System.Text.RegularExpressions;
    
  2. Agregue una variable y un método auxiliar a la clase como se muestra en el siguiente código.

    // Storage for the order ID value.
    private int parsedOrderID;
    
    /// <summary>
    /// Verifies that an order ID is present and contains valid characters.
    /// </summary>
    private bool IsOrderIDValid()
    {
        // Check for input in the Order ID text box.
        if (txtOrderID.Text == "")
        {
            MessageBox.Show("Please specify the Order ID.");
            return false;
        }
    
        // Check for characters other than integers.
        else if (Regex.IsMatch(txtOrderID.Text, @"^\D*$"))
        {
            // Show message and clear input.
            MessageBox.Show("Customer ID must contain only numbers.");
            txtOrderID.Clear();
            return false;
        }
        else
        {
            // Convert the text in the text box to an integer to send to the database.
            parsedOrderID = Int32.Parse(txtOrderID.Text);
            return true;
        }
    }
    
  3. Complete los cuerpos de método para los cuatro controladores de eventos generados con clic de botón, como se muestra en el código siguiente.

    /// <summary>
    /// Executes a t-SQL SELECT statement to obtain order data for a specified
    /// order ID, then displays it in the DataGridView on the form.
    /// </summary>
    private void btnFindByOrderID_Click(object sender, EventArgs e)
    {
        if (IsOrderIDValid())
        {
            using (SqlConnection connection = new SqlConnection(Properties.Settings.Default.connString))
            {
                // Define a t-SQL query string that has a parameter for orderID.
                const string sql = "SELECT * FROM Sales.Orders WHERE orderID = @orderID";
    
                // Create a SqlCommand object.
                using (SqlCommand sqlCommand = new SqlCommand(sql, connection))
                {
                    // Define the @orderID parameter and set its value.
                    sqlCommand.Parameters.Add(new SqlParameter("@orderID", SqlDbType.Int));
                    sqlCommand.Parameters["@orderID"].Value = parsedOrderID;
    
                    try
                    {
                        connection.Open();
    
                        // Run the query by calling ExecuteReader().
                        using (SqlDataReader dataReader = sqlCommand.ExecuteReader())
                        {
                            // Create a data table to hold the retrieved data.
                            DataTable dataTable = new DataTable();
    
                            // Load the data from SqlDataReader into the data table.
                            dataTable.Load(dataReader);
    
                            // Display the data from the data table in the data grid view.
                            this.dgvCustomerOrders.DataSource = dataTable;
    
                            // Close the SqlDataReader.
                            dataReader.Close();
                        }
                    }
                    catch
                    {
                        MessageBox.Show("The requested order could not be loaded into the form.");
                    }
                    finally
                    {
                        // Close the connection.
                        connection.Close();
                    }
                }
            }
        }
    }
    
    /// <summary>
    /// Cancels an order by calling the Sales.uspCancelOrder
    /// stored procedure on the database.
    /// </summary>
    private void btnCancelOrder_Click(object sender, EventArgs e)
    {
        if (IsOrderIDValid())
        {
            // Create the connection.
            using (SqlConnection connection = new SqlConnection(Properties.Settings.Default.connString))
            {
                // Create the SqlCommand object and identify it as a stored procedure.
                using (SqlCommand sqlCommand = new SqlCommand("Sales.uspCancelOrder", connection))
                {
                    sqlCommand.CommandType = CommandType.StoredProcedure;
    
                    // Add the order ID input parameter for the stored procedure.
                    sqlCommand.Parameters.Add(new SqlParameter("@orderID", SqlDbType.Int));
                    sqlCommand.Parameters["@orderID"].Value = parsedOrderID;
    
                    try
                    {
                        // Open the connection.
                        connection.Open();
    
                        // Run the command to execute the stored procedure.
                        sqlCommand.ExecuteNonQuery();
                    }
                    catch
                    {
                        MessageBox.Show("The cancel operation was not completed.");
                    }
                    finally
                    {
                        // Close connection.
                        connection.Close();
                    }
                }
            }
        }
    }
    
    /// <summary>
    /// Fills an order by calling the Sales.uspFillOrder stored
    /// procedure on the database.
    /// </summary>
    private void btnFillOrder_Click(object sender, EventArgs e)
    {
        if (IsOrderIDValid())
        {
            // Create the connection.
            using (SqlConnection connection = new SqlConnection(Properties.Settings.Default.connString))
            {
                // Create command and identify it as a stored procedure.
                using (SqlCommand sqlCommand = new SqlCommand("Sales.uspFillOrder", connection))
                {
                    sqlCommand.CommandType = CommandType.StoredProcedure;
    
                    // Add the order ID input parameter for the stored procedure.
                    sqlCommand.Parameters.Add(new SqlParameter("@orderID", SqlDbType.Int));
                    sqlCommand.Parameters["@orderID"].Value = parsedOrderID;
    
                    // Add the filled date input parameter for the stored procedure.
                    sqlCommand.Parameters.Add(new SqlParameter("@FilledDate", SqlDbType.DateTime, 8));
                    sqlCommand.Parameters["@FilledDate"].Value = dtpFillDate.Value;
    
                    try
                    {
                        connection.Open();
    
                        // Execute the stored procedure.
                        sqlCommand.ExecuteNonQuery();
                    }
                    catch
                    {
                        MessageBox.Show("The fill operation was not completed.");
                    }
                    finally
                    {
                        // Close the connection.
                        connection.Close();
                    }
                }
            }
        }
    }
    
    /// <summary>
    /// Closes the form.
    /// </summary>
    private void btnFinishUpdates_Click(object sender, EventArgs e)
    {
        this.Close();
    }
    

Prueba de la aplicación

Ejecute la aplicación e intente crear algunos clientes y pedidos para comprobar que todo funciona según lo previsto. Para comprobar que la base de datos se actualiza con los cambios, abra el nodo Tablas en el Explorador de servidores, haga clic con el botón derecho en los nodos Customers y Orders y elija Mostrar datos de tabla.