Cómo crear listas de tuplas para almacenar datos en memoria. Como ejemplo conectaremos con un servidor MySQL, ejecutaremos una consulta SQL y los registros que se obtienen se almacenan en una lista de tuplas (en memoria). Además, como ejemplo también se instancia una clase a la que se le pasa como parámetro la lista de tuplas y la guarda en un fichero de texto CSV.
- Requisitos para trabajar con listas, tuplas y listas de tuplas en C#.
- Las tuplas (Tuple) en C#.
- Listas (List) en C#.
- Lista de tuplas en C#.
- Guardar registros de consulta SQL de tabla de base de datos en memoria en una lista de tuplas y en fichero CSV con C#.
- Descarga de la aplicación completa de ejemplo en C#.
Requisitos para trabajar con listas, tuplas y listas de tuplas en C#
El único requisito es disponer del IDE de desarrollo Visual Studio .Net, en nuestro caso usaremos la versión gratuita Visual Studio .Net Commnuty Edition. En el siguiente enlace explicamos cómo descargarlo e instalarlo:
En el caso de querer guardar el contenido de una tabla de una base de datos (o de la ejecución de una consulta SQL), evidentemente necesitaremos tener acceso al servidor de base de datos. En el ejemplo de este tutorial accederemos a un servidor de base de datos MySQL. Para ello deberemos tener la dirección IP del servidor (o el nombre DNS), un usuario y una contraseña.
Para el caso de acceso a MySQL Server desde C#, podremos seguir las instrucciones del siguiente manual:
Desarrollar aplicación C# con acceso nativo a MySQL Server mediante ADO.NET.
Las tuplas (Tuple) en C#
Una tupla es una estructura de datos que tiene un número específico y una secuencia de valores. Admite elementos de diferentes tipos de datos (string, DateTime, int, etc.).
Las tuplas se utilizan normalmente para:
- Representar un único conjunto de datos. Por ejemplo, una tupla puede representar un registro de base de datos y sus componentes pueden representar campos (columnas) individuales del registro.
- Facilitar el acceso y la manipulación de un conjunto de datos.
- Devolver varios valores de un método sin usar out para paso de parámetros por referencia en C# o ByRef para paso de parámetros por referencia en Visual Basic.
En una tupla, por ejemplo, se puede almacenar el resultado de la ejecución de una consulta SQL que devuelve registros de una tabla. Esto nos permitirá utilizar esta tupla con los datos de los registros «en memoria» para otros métodos de nuestra aplicación, entre otras cosas.
Hay varias formas de crear tuplas, algua de ellas:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
private void btCrearListaTuplas_Click(object sender, EventArgs e) { //Crear tupla indicando los elementos que contendrá y su tipo de datos //Y agregando su valor al crearla var tuplaPrueba = new Tuple<string, int, DateTime>("Prueba de tupla con new", 125, DateTime.Now); //Acceder a los datos de la tupla y mostrar datos en un TextBox txtContenidoListaTuplas.Text = tuplaPrueba.Item1 + " | " + tuplaPrueba.Item3 + " | " + tuplaPrueba.Item2; //Agregamos salto de línea en el TextBox txtContenidoListaTuplas.Text = txtContenidoListaTuplas.Text + Environment.NewLine; //Crear tupla directamente agregando los elementos que contendrá var tuplaPrueba2 = Tuple.Create("Prueba de tupla con create", 125, DateTime.Now); //Acceder a los datos de la tupla y mostrar datos en un TextBox txtContenidoListaTuplas.Text = txtContenidoListaTuplas.Text + tuplaPrueba2.Item1 + " | " + tuplaPrueba2.Item3 + " | " + tuplaPrueba2.Item2; //Agregamos salto de línea en el TextBox txtContenidoListaTuplas.Text = txtContenidoListaTuplas.Text + Environment.NewLine; //Crear tupla dando nombre a cada campo (string MiColumna1, int MiColumna2, DateTime MiColumna3) tuplaPrueba3 = ("Prueba de tupla con nombres", 125, DateTime.Now); //Acceder a los datos de la tupla con nombres de campo y mostrar datos en un TextBox txtContenidoListaTuplas.Text = txtContenidoListaTuplas.Text + tuplaPrueba3.MiColumna1 + " | " + tuplaPrueba3.MiColumna3 + " | " + tuplaPrueba3.MiColumna2; } |
El resultado de la ejecución del código anterior:
La declaración de una tupla admite, como máximo, ocho campos (óctupla).
Los datos contenidos en una tupla son invariables, no se pueden modificar una vez creada y asignados sus valores.
Listas (List) en C#
Representa una lista de objetos fuertemente tipados a la que se puede obtener acceso por índice. Proporciona métodos para buscar, ordenar y manipular listas.
Para el caso de este artículo usaremos una lista de tuplas, de forma que podremos almacenar un número indefinido de tuplas dentro de una lista. Esto nos permitirá, como veremos más adelante, poder almacenar el resultado de una consulta SQL en una lista de tuplas.
Un ejemplo de creación de una lista y manipulación de sus datos (agregar elementos, recorrerlos, etc.):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
private void btCrearListaTuplas_Click(object sender, EventArgs e) { //Creamos una lista de string List<string> dinosaurios = new List<string>(); //Agreamos elementos en la lista dinosaurios.Add("Tiranosaurio rex"); dinosaurios.Add("Triceratops"); dinosaurios.Add("Diplodocus"); dinosaurios.Add("Velociraptor"); //Iteramos (recorremos) la lista y mostramos su contenido en un TextBox foreach (string dinosaurio in dinosaurios) { //Añadimos el elemento actual de la lista a un TextBox txtContenidoListaTuplas.Text = txtContenidoListaTuplas.Text + dinosaurio; //Añadimos una nueva línea en el TextBox txtContenidoListaTuplas.Text = txtContenidoListaTuplas.Text + Environment.NewLine; } } |
El resultado de la ejecución del código anterior:
Lista de tuplas en C#
Tras conocer las tuplas y las listas, ahora usaremos la «potencia» de ambas estructuras de datos para «unirlas», de esta forma podremos tener listas de tuplas, como si de registros de una base de datos se tratase.
A continuación mostramos un ejemplo de declaración de una lista de tuplas con cuatro campos (columnas, elementos), le agregamos valores (registros) y los mostramos por pantalla:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
private void btCrearListaTuplas_Click(object sender, EventArgs e) { //Creamos una lista de tuplas con un string, una fecha-hora, y otros dos string var listaTuplas = new List <Tuple<string, DateTime, string, string>>(); //Para probar, rellenamos la lista de tuplas con valores listaTuplas.Add(Tuple.Create("Col1 - Fila 1", DateTime.Now, "Col3 - Fila 1", "Col4 - Fila 1")); listaTuplas.Add(Tuple.Create("Col1 - Fila 2", DateTime.Now.AddDays(1), "Col3 - Fila 2", "Col4 - Fila 2")); listaTuplas.Add(Tuple.Create("Col1 - Fila 3", DateTime.Now.AddDays(2), "Col3 - Fila 3", "Col4 - Fila 3")); listaTuplas.Add(Tuple.Create("Col1 - Fila 4", DateTime.Now.AddDays(3), "Col3 - Fila 4", "Col4 - Fila 4")); //Recorremos la lista de tuplas y mostramos el contenido de la lista, //de cada elemento de la lista y de cada columna de la tupla //en un TextBox, separando cada tupla en una línea int numTupla = 0; foreach (var inci in listaTuplas) { numTupla = numTupla + 1; txtContenidoListaTuplas.Text = txtContenidoListaTuplas.Text + "Tupla : " + numTupla.ToString() + " -> " + inci.Item1 + " | " + inci.Item3 + " | " + inci.Item4 + " | " + inci.Item2 + Environment.NewLine; } } |
El resultado de la ejecución del código anterior:
Guardar registros de consulta SQL de tabla de base de datos en memoria en una lista de tuplas y en fichero CSV con C#
Tras conocer las tuplas, las listas y las lista de tuplas, vamos a mostrar un ejemplo de código fuente en C# que accede a una base de datos MySQL Server, ejecuta una consulta SQL y, los registros que obtiene de dicha ejecución, los almacena en una lista de tuplas (en memoria). Además, también almacena la lista de tuplas en un fichero de texto CSV.
A continuación se muestra el código fuente en C# de la clase principal formPrincipal. Dicho formulario tiene los siguientes componentes:
El código fuente completo puede descargarse aquí, a continuación se lista el código fuente de la clase formPrincipal, que incluye incluye comentarios en las líneas más importantes, explicando su cometido:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
using MySql.Data.MySqlClient; using System; using System.Collections.Generic; using System.Data; using System.Windows.Forms; namespace TuplasGuardarDatosProyectoA { public partial class formPrincipal : Form { //Conexión a la base de datos MySQL MySqlConnection conexionBD; public formPrincipal() { InitializeComponent(); } private void btCrearListaTuplas_Click(object sender, EventArgs e) { if (txtFicheroGuardarListaTuplas.Text == "") MessageBox.Show("Debe elegir una carpeta y nombre de fichero en el que " + "se guardará la lista de tuplas obtenida de la consulta " + "SQL de la base de datos.", "Elegir fichero...", MessageBoxButtons.OK, MessageBoxIcon.Warning); else { //Datos de conexión al servidor de base de datos MySQL Server string servidor = "servidor_mysql"; int puerto = 3306; string bd = "bd_proyectoa"; string usuario = "root"; string contrasena = "contraseña"; string connStr = String.Format("server={0};port={1};user id={2}; password={3}; " + "database={4}; pooling=true;" + "Allow Zero Datetime=False;Convert Zero Datetime=True", servidor, puerto, usuario, contrasena, bd); try { //Conectamos al servidor de MySQL Server conexionBD = new MySqlConnection(connStr); //Consulta SQL que se ejecutará en el servidor de MySQL string sqlConsulta = "select codigo, nombre, dni, fecha" + " from usuario" + " where upper(nombre) like 'ALO%'"; MySqlCommand comandoMySQL = new MySqlCommand(); conexionBD.Open(); comandoMySQL.Connection = conexionBD; comandoMySQL.CommandType = CommandType.Text; comandoMySQL.CommandText = sqlConsulta; //Creamos una lista de tuplas donde almacenaremos el resultado de la consulta SQL var listaRegistros = new List<Tuple<int, string, string, DateTime>>(); //Preparamos el reader con los registros de la consulta SQL MySqlDataReader readerConsultaSQL = comandoMySQL.ExecuteReader(); //Recorremos los registros que devuelve la consulta SQL int codigo; string nombre, dni; DateTime fecha; while (readerConsultaSQL.Read()) { //Comprobamos los posibles nulos de cada campo de la consulta SQL if (!readerConsultaSQL.IsDBNull(readerConsultaSQL.GetOrdinal("codigo"))) codigo = Convert.ToInt32(readerConsultaSQL["codigo"]); else codigo = 0; if (!readerConsultaSQL.IsDBNull(readerConsultaSQL.GetOrdinal("nombre"))) nombre = readerConsultaSQL["nombre"].ToString(); else nombre = ""; if (!readerConsultaSQL.IsDBNull(readerConsultaSQL.GetOrdinal("dni"))) dni = readerConsultaSQL["dni"].ToString(); else dni = ""; if (!readerConsultaSQL.IsDBNull(readerConsultaSQL.GetOrdinal("fecha"))) fecha = Convert.ToDateTime(readerConsultaSQL["fecha"]); else fecha = DateTime.Now; //Guardamos cada registro en una tupla de la lista listaRegistros.Add(Tuple.Create(codigo, nombre, dni, fecha)); } //Como prueba, recorremos la lista de tuplas y mostramos su contenido en un TextBox int numTupla = 0; string tuplas = ""; foreach (var tuplaActual in listaRegistros) { numTupla = numTupla + 1; tuplas = tuplas + "Tupla : " + numTupla.ToString() + " -> " + tuplaActual.Item1 + " | " + tuplaActual.Item2 + " | " + tuplaActual.Item3 + " | " + tuplaActual.Item4 + Environment.NewLine; } txtContenidoListaTuplas.Text = tuplas; //Ejemplo para usar la lista de tuplas generada en otra clase //Que guardará la lista en un fichero de texto ListaTuplasRegistrosMemoria lsTuplasMem = new ListaTuplasRegistrosMemoria(listaRegistros); bool resultado = lsTuplasMem.GuardarListaTuplasFichero(txtFicheroGuardarListaTuplas.Text); if (resultado) MessageBox.Show("Las tuplas se han guardado en el fichero: " + txtFicheroGuardarListaTuplas.Text, "Tuplas guardadas en fichero...", MessageBoxButtons.OK, MessageBoxIcon.Information); } catch (MySqlException ex) { MessageBox.Show("Error al conectar al servidor de MySQL: " + ex.Message, "Error al acceder a la BD...", MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { conexionBD.Close(); } } } private void btGuardarTuplas_Click(object sender, EventArgs e) { OpenFileDialog dialogiAbrirFichero = new OpenFileDialog(); dialogiAbrirFichero.InitialDirectory = Application.StartupPath; dialogiAbrirFichero.Filter = "Ficheros CSV (*.csv)|*.csv|Todos los ficheros (*.*)|*.*"; dialogiAbrirFichero.FilterIndex = 1; dialogiAbrirFichero.RestoreDirectory = true; dialogiAbrirFichero.CheckFileExists = false; if (dialogiAbrirFichero.ShowDialog() == DialogResult.OK) txtFicheroGuardarListaTuplas.Text = dialogiAbrirFichero.FileName; } } } |
Se crea una clase llamada ListaTuplasRegistrosMemoria con el siguiente código C#:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; namespace TuplasGuardarDatosProyectoA { class ListaTuplasRegistrosMemoria { //Lista de tuplas List<Tuple<int, string, string, DateTime>> listaRegistros; //Constructor al que se le pasa la lista de tuplas como parámetro public ListaTuplasRegistrosMemoria(List<Tuple<int, string, string, DateTime>> listaRegistros) { this.listaRegistros = listaRegistros; } //Método para guardar los datos de la lista de tuplas en fichero de texto public bool GuardarListaTuplasFichero (string fichero) { try { StringBuilder datosTuplas = new StringBuilder(); //Encabezado del fichero datosTuplas.AppendLine("\"Código\",\"Nombre\",\"DNI\",\"Fecha\""); //Recorremos cada elemento de la lista de tuplas para formatearlo en el StringBuilder foreach (var registroActual in listaRegistros) { datosTuplas.AppendLine("\"" + registroActual.Item1 + "\",\"" + registroActual.Item2 + "\",\"" + registroActual.Item3 + "\",\"" + registroActual.Item4 + "\""); } //Guardamos el StringBuilder en el fichero de texto pasado por parámetro System.IO.File.WriteAllText(fichero, datosTuplas.ToString()); return true; } catch (Exception err) { MessageBox.Show("Error al guardar las tuplas en el fichero de texto: " + fichero + err.Message, "Error al guardar tuplas...", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } } } } |
La aplicación de ejemplo en ejecución realiza las siguientes tareas:
- Realizará una conexión con un servidor de base de datos MySQL. Para la prueba de la aplicación los datos de conexión se pasan por código.
- Se ejecuta una consulta SQL, que también se pasa por código.
- Los registros que devuelve la ejecución de la consulta SQL se almacenan en una lista de tuplas, en memoria.
- Se instancia una clase de ListaTuplasRegistrosMemoria como ejemplo de paso de parámetro de la lista de tuplas en memoria.
- Dicha clase guardará en fichero CSV (con valores separados por comillas dobles y comas) la lista de tuplas.
En la siguiente imagen podemos ver el resultado, pues la aplicación también muestra la lista de tuplas (los registros de la base de datos) por pantalla en un TextBox:
Descarga de la aplicación completa de ejemplo en C#
A continuación dejamos el enlace para la descarga de la aplicación completa que accede a un servidor MySQL, guarda el resultado de la consulta SQL en una lista de tuplas y, a su vez, guarda la lista de tuplas en un fichero CSV: