Cómo usar el OCR PetaPoco para accesos (insert, select, update, delete) a servidor de MySQL/MariaDB con Visual Studio .Net y C# (CSharp). PetaPoco admite otros motores de base de datos como Oracle, SQL Server, Firebird, SQLite, MS Access, PostgreSQL, etc.). PetaPoco es un mini ORM (Object–role modeling) que nos permitirá realizar tareas de acceso a base de datos de forma muy sencilla y eficiente. Como ejemplo, mostramos un formulario que permite añadir, eliminar, modificar y listar facturas.

Preparar tabla en base de datos MariaDB MySQL

Para el ejemplo de acceso a servidor MySQL MariaDB con PetaPoco, usaremos una tabla con la siguiente estructura (script SQL de creación de tabla):

CREATE TABLE facturas.factura (
  codigo INT NOT NULL AUTO_INCREMENT,
  fecha DATETIME NULL,
  cliente VARCHAR(150) NULL,
  importe DECIMAL(10,2) NULL,
  numero VARCHAR(20) NULL,
  observacion TEXT NULL,
  PRIMARY KEY (codigo));

Dispondremos, por lo tanto, de una tabla llamada «fatura» con los campos: codigo (autoincremento y clave primaria), fecha, cliente, importe, numero y observacion.

Como es lógico, dispondremos de un servidor de MySQL Server o MariaDB Server, con dicha tabla creada. En el siguiente artículo explicamos cómo montar un servidor de base de datos MySQL MariaDB en Linux:

Paquete de acceso nativo al servidor MySQL MariaDB con C#

PetaPoco no incluye el acceso en sí al servidor correspondiente de base de datos. Necesitaremos por lo tanto el paquete correspondiente para acceso nativo al servidor que queramos usar de base de datos, en nuestro caso MySQL Server o MariaDB Server.

En el siguiente enlace explicamos cómo usar el paquete para Visual Studio .Net CSharp de MySQL, disponible en su web oficial:

Instalar PetaPoco en nuestro proyecto Visual Studio .Net CSharp

Crearemos, si no lo hemos hecho aún, un proyecto Visual Studio .Net C# (CSharp):

Instalar Petapoco en nuestro proyecto Visual Studio .Net CSharp

Introduciremos el nombre del proyecto:

Instalar Petapoco en nuestro proyecto Visual Studio .Net CSharp

Elegiremos la versión de .NET 6.0 (la última disponible):

Instalar Petapoco en nuestro proyecto Visual Studio .Net CSharp

Para instalar el paquete PetaPoco, desde nuestro proyecto, pulsaremos en el menú «Herramientas» y en «Administrador de paquetes NuGet » – «Administrar paquetes NuGet para la solución…»:

Instalar Petapoco en nuestro proyecto Visual Studio .Net CSharp

Pulsaremos en «Examniar» [1], escribiremos «petapoco» en buscar [2]. Seleccionaremos «PetaPoco.Compiled» versión 6.0.566 [3]. Marcaremos el proyecto donde se instalará [4] y pulsaremos en «Instalar» [5]:

Instalar Petapoco en nuestro proyecto Visual Studio .Net CSharp

Una vez instalado nos indicará los paquetes instalados:

  • PetaPoco.Compiled.6.0.566.
  • System.Reflection.Emit.ILGeneration.4.7.0.
  • System.Reflection.Emit.Lighwight.4.7.0.

Pulsaremos «Aceptar» y ya tendremos instalado el paquete PetaPoco para nuestra proyecto C# .Net:

Instalar Petapoco en nuestro proyecto Visual Studio .Net CSharp

En las dependencias de paquetes de nuestra solución nos habrá añadido «PetaPoco.Compiled»:

Instalar Petapoco en nuestro proyecto Visual Studio .Net CSharp

Agregar clases para la aplicación de ejemplo de gestión de facturas con MariaDB MySQL y PetaPoco en C#

Agregaremos a nuestro proyecto las clases necesarias y su código para realizar todas las tareas de la aplicación: guardar en fichero de configuración los datos de acceso al servidor, cifrar contraseña, guardar datos de log (para depuración), acceso a la base de datos MariaDB o MySQL con PetaPoco, tabla de facturas, métodos para listar e insertar facturas y clientes, etc..

Para añadir una clase, desde Visual Studio .Net, con nuestro proyecto abierto, pulsaremos con el botón derecho sobre la solución y elegiremos «Agregar» – «Clase…»:

Agregar clases para la aplicación de ejemplo de gestión de facturas con MariaDB MySQL y PetaPoco en C#

Empezaremos por crear las clases con las utilidades necesarias para el resto de clases. Empezaremos por la clase que escribirá en fichero de log cualquier error o dato que queramos almacenar para depuración. Esta clase se llamará Log y tendrá el siguiente código fuente C#:

namespace ProyectoAAccesoMySQLPetaPoco
{
    static class Log
    {
        //Guardar mensaje en fichero de texto o también mostrarlo por consola
        public static void EsLog(string mensaje, Boolean mostrarConsola)
        {
            mensaje = QuitarSaltos(mensaje);
            if (mostrarConsola)
                MonstrarMensajeConsola(mensaje);
            EscribirLineaFichero(mensaje);
        }

        //Muestra el mensaje por consola MS-DOS (solo para aplicaciones de consola)
        private static void MonstrarMensajeConsola(string mensaje)
        {            
            Console.WriteLine($"{DateTime.Now:dd/MM/yyyy hh:mm:ss} {mensaje}");
        }

        //Escribe el mensaje en un fichero en la carpeta del ejecutable
        private static void EscribirLineaFichero(string mensaje)
        {
            try
            {
                FileStream fs = new(@AppDomain.CurrentDomain.BaseDirectory +
                    "estado.log", FileMode.OpenOrCreate, FileAccess.Write);
                StreamWriter m_streamWriter = new(fs);
                m_streamWriter.BaseStream.Seek(0, SeekOrigin.End);
                m_streamWriter.WriteLine($"{DateTime.Now:dd/MM/yyyy hh:mm:ss} {mensaje}");
                m_streamWriter.Flush();
                m_streamWriter.Close();
            }
            catch
            {
                //Silenciosa
            }
        }

        //Quita posibles saltos de línea del mensaje
        private static string QuitarSaltos (string mensaje)
        {
            mensaje = mensaje.Replace(Environment.NewLine, " | ");
            mensaje = mensaje.Replace("\r\n", " | ").Replace("\n", " | ").Replace("\r", " | ");
            return mensaje;
        }
    }
}

Crearemos otra clase, llamada Config, que será la que escribirá en fichero de configuración los datos de acceso al servidor de base de datos (IP, usuario, contraseña, etc.), con el siguiente código fuente C Sharp:

using System.Configuration;

namespace ProyectoAAccesoMySQLPetaPoco

{
    static class Config
    {
        //Lee un valor de una clave en el fichero de configuración XML de la aplicación
        public static string Leer(string clave)
        {
            try
            {
                return ConfigurationManager.AppSettings[clave] ?? "";
            }
            catch (Exception error)
            {
                Log.EsLog ($"Error al leer valor de configuración: {error.GetType()} {error.Message}", false);
                return "";
            }
        }
        

        //Guarda un valor en una clave en el fichero de configuración XML de la aplicación
        public static void Guardar(string clave, string valor)
        {
            try
            {
                Configuration ficheroConfXML =
                    ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

                //Eliminamos la clave actual (si existe), de lo contrario los valores
                //se irán acumulando separados por coma
                ficheroConfXML.AppSettings.Settings.Remove(clave);

                //Asignamos el valor en la clave indicada
                ficheroConfXML.AppSettings.Settings.Add(clave, valor);

                //Guardamos los cambios definitivamente en el fichero de configuración
                ficheroConfXML.Save(ConfigurationSaveMode.Modified);
            }
            catch (Exception error)
            {
                Log.EsLog($"Error al guardar valor de configuración: {error.GetType()} {error.Message}", false);
            }
        }
    }
}

Añadiremos otra clase, con el nombre Cifrar, que será la encargada de cifrar la contraseña para guardarla en el fichero de configuración, tendrá el siguiente código fuente C Sharp:

namespace ProyectoAAccesoMySQLPetaPoco
{
    using System;
    using System.IO;
    using System.Security.Cryptography;
    using System.Text;
    static class Cifrar
    {
        public static string CifrarAES(string textoCifrar, string palabraPaso,
           string valorRGBSalt, string algoritmoEncriptacionHASH,
           int iteraciones, string vectorInicial, int tamanoClave)
        {
            try
            {
                byte[] InitialVectorBytes = Encoding.ASCII.GetBytes(vectorInicial);
                byte[] saltValueBytes = Encoding.ASCII.GetBytes(valorRGBSalt);
                byte[] plainTextBytes = Encoding.UTF8.GetBytes(textoCifrar);

                PasswordDeriveBytes password =
                    new PasswordDeriveBytes(palabraPaso, saltValueBytes,
                        algoritmoEncriptacionHASH, iteraciones);

                byte[] keyBytes = password.GetBytes(tamanoClave / 8);

                RijndaelManaged symmetricKey = new RijndaelManaged();

                symmetricKey.Mode = CipherMode.CBC;

                ICryptoTransform encryptor =
                    symmetricKey.CreateEncryptor(keyBytes, InitialVectorBytes);

                MemoryStream memoryStream = new MemoryStream();

                CryptoStream cryptoStream =
                    new(memoryStream, encryptor, CryptoStreamMode.Write);

                cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);

                cryptoStream.FlushFinalBlock();

                byte[] cipherTextBytes = memoryStream.ToArray();

                memoryStream.Close();
                cryptoStream.Close();

                string textoCifradoFinal = Convert.ToBase64String(cipherTextBytes);

                return textoCifradoFinal;
            }
            catch
            {
                return "";
            }
        }


        public static string DescifrarAES(string textoCifrado, string palabraPaso,
            string valorRGBSalt, string algoritmoEncriptacionHASH,
            int iteraciones, string vectorInicial, int tamanoClave)
        {
            try
            {
                byte[] InitialVectorBytes = Encoding.ASCII.GetBytes(vectorInicial);
                byte[] saltValueBytes = Encoding.ASCII.GetBytes(valorRGBSalt);

                byte[] cipherTextBytes = Convert.FromBase64String(textoCifrado);

                PasswordDeriveBytes password =
                    new(palabraPaso, saltValueBytes,
                        algoritmoEncriptacionHASH, iteraciones);

                byte[] keyBytes = password.GetBytes(tamanoClave / 8);

                RijndaelManaged symmetricKey = new RijndaelManaged();

                symmetricKey.Mode = CipherMode.CBC;

                ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, InitialVectorBytes);

                MemoryStream memoryStream = new MemoryStream(cipherTextBytes);

                CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);

                byte[] plainTextBytes = new byte[cipherTextBytes.Length];

                int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);

                memoryStream.Close();
                cryptoStream.Close();

                string textoDescifradoFinal = Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);

                return textoDescifradoFinal;
            }
            catch
            {
                return "";
            }
        }
    }
}

Crearemos la clase de acceso a la base de datos. Esta clase será la que contenga los métodos de conexión con el servidor de base de datos. Lo habitual será obtener los datos de acceso al servidor de base de datos desde un fichero de configuración de la aplicación, usando la clase anterior Config. La clase para acceso al servidor de base de datos se llamará Peta y tendrá el siguiente código C Sharp:

namespace ProyectoAAccesoMySQLPetaPoco
{
    using MySql.Data.MySqlClient;
    using PetaPoco;
    using System;
    using System.Data;
    using System.Threading;

    public sealed class Peta
    {
        private static readonly Lazy<Peta> lazy = new Lazy<Peta>(() => new Peta());

        private readonly Database _database;

        public static Database BD => Instance.GetDatabase();

        private Peta()
        {
            string servidor, puerto, bd, usuario, contrasena;

            servidor = Config.Leer("Servidor");
            puerto = Config.Leer("Puerto");
            bd = Config.Leer("Base de datos");
            usuario = Config.Leer("Usuario");
            contrasena = Cifrar.DescifrarAES(Config.Leer("Contraseña"),
                "Encriptad0", "SalT", "MD5", 22, "1234567891234567", 128);

            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;Connect Timeout=10;ConnectionLifetime=60",
                    servidor, puerto, usuario, contrasena, bd);
            _ = new MySqlConnectionStringBuilder(connStr)
            {
                AllowZeroDateTime = true,
                ConvertZeroDateTime = true
            };

            _database = new Database(new MySqlConnection(connStr))//builder.ConnectionString, "MySql.Data.MySqlClient")
            {
                EnableAutoSelect = false,
                EnableNamedParams = true,
                // ForceDateTimesToUtc = true,
                CommandTimeout = 60
            };
            //_database.KeepConnectionAlive = true;
            
        }

        public static Peta Instance
        {
            get
            {
                return lazy.Value;
            }
        }

        //Conexión con el servidor de base de datos
        public Database GetDatabase()
        {
            int intentosMáximos = 5;
            while (true)
            {
                try
                {

                    if (_database.Connection.State == ConnectionState.Closed)
                    {
                        _database.Connection.Open();
                    }

                    return _database;
                }
                catch (MySqlException ex)
                {
                    //Si se produce un error de conexión de tipo 0, 1042, 1044 o 1045 se realizan 5 intentos de conexión
                    if (intentosMáximos > 0 && (ex.Number == 0 || ex.Number == 1042 || ex.Number == 1043 || ex.Number == 1044 || ex.Number == 1045))
                    {
                        intentosMáximos--;
                        Thread.Sleep(50);
                    }
                    else
                    {
                        throw;                        
                    }
                }
                catch (Exception ex) 
                {
                    Log.EsLog($"Error al conectar al servidor de base de datos: {ex.Message}", false);
                    MessageBox.Show($"Error al conectar al servidor de base de datos. Error: {ex.Message}",
                        "Error al conectar a la BD...",MessageBoxButtons.OK,MessageBoxIcon.Error);
                }
            }
        }
    }
}

Crearemos la clase para la tabla de facturas de la base de datos, la llamaremos BDFacturas y tendrá el siguiente código fuente C#:

using PetaPoco;

namespace ProyectoAAccesoMySQLPetaPoco
{
    [TableName("factura")]
    [PrimaryKey("codigo")]
    public class BDFactura
    {
        [Column("codigo")]
        public int Codigo { get; set; }

        [Column("fecha")]
        public DateTime fecha { get; set; }

        [Column("cliente")]
        public string cliente { get; set; }

        [Column("importe")]
        public decimal importe { get; set; }

        [Column("observacion")]
        public string observacion { get; set; }

        [Column("numero")]
        public string numero { get; set; }

        //Constructor vacío para instanciar sin argumentos
        public BDFactura() 
        {
            Codigo = 0;
            fecha = DateTime.Now;
            cliente = "";
            importe = 0;
            observacion = "";
            numero = "";
        }

        //Constructor con clase de BDFactura para asignar los valores
        //al instancionar la clase con este constructor
        public BDFactura(BDFactura elm, int codigoElemento)
        {
            Codigo = codigoElemento;
            fecha = elm.fecha;
            cliente = elm.cliente;
            importe = elm.importe;
            observacion = elm.observacion;
            numero = elm.numero;
        }
    }
}

Crearemos una última clase, llamada Pro, que será la que contenga todos los métodos que utilizaremos en la aplicación para insertar facturas, obtener lista de facturas, obtener lista de clientes, etc.. El código fuente C Sharp será:

namespace ProyectoAAccesoMySQLPetaPoco
{
    class Pro
    {
        //Método que obtiene una lista de clientes de la tabla "factura", campo "cliente"
        //Se le pasa como parámetro un ComboBox y es ahí donde mostrará el resultado
        public static void ObtenerClientes (ComboBox lista)
        {
            try
            {
                //Cargamos la lista de clientes en el desplegable
                List<BDFactura> clientes = Peta.BD.Fetch<BDFactura>("select distinct(cliente) from factura order by cliente");
                foreach (var clienteActual in clientes)
                {
                    lista.Items.Add(clienteActual.cliente);
                }
            }
            catch (Exception ex) 
            {
                MessageBox.Show($"Error al obtener clientes de las facturas. Error: {ex.Message}",
                    "Error al obtener clientes...", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        //Método que obtiene todas las facturas de la tabla "factura"
        //Se le pasa como parámetro un ListView y es ahí donde mostrará el resultado
        public static void ObtenerFacturas (ListView lista)
        {
            try
            {
                //Establecemos las propiedades del ListView
                lista.Clear();
                lista.View = View.Details;
                lista.GridLines = true;
                lista.FullRowSelect = true;

                var lFacturas = ObtenerFacturas();
                if (lFacturas != null)
                {
                    //Cargamos una lista de elementos de la clase BDFactura con los registros de la tabla "factura"
                    List<BDFactura> facturas = lFacturas;

                    //Añadimos las columnas al ListView con su formato para mostrar los campos de los registros de la tabla factura
                    lista.Columns.Add("Código", 90, HorizontalAlignment.Left);
                    lista.Columns.Add("Cliente", 330, HorizontalAlignment.Left);
                    lista.Columns.Add("Importe", 120, HorizontalAlignment.Right);
                    lista.Columns.Add("Número", 100, HorizontalAlignment.Left);
                    lista.Columns.Add("Fecha", 180, HorizontalAlignment.Left);
                    lista.Columns.Add("Observación", 280, HorizontalAlignment.Left);

                    //Recorremos cada registro de la tabla factura para añadir una línea al ListView
                    _ = new ListViewItem();
                    foreach (var factActual in facturas)
                    {
                        ListViewItem filasListView = new(factActual.Codigo.ToString());
                        filasListView.SubItems.Add(factActual.cliente);
                        filasListView.SubItems.Add(factActual.importe.ToString());
                        filasListView.SubItems.Add(factActual.numero);
                        filasListView.SubItems.Add(factActual.fecha.ToString());
                        filasListView.SubItems.Add(factActual.observacion);
                        lista.Items.Add(filasListView);
                    }
                }
            }
            catch (Exception ex) 
            {
                MessageBox.Show($"Error al obtener las facturas. Error: {ex.Message}",
                    "Error al obtener facturas...", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        //Obtiene una lista de facturas de la base de datos usando PetaPoco, la devuelve en una lista de objetos de la clase BDFacturas
        //Ordenamos el resultado para que la primera fila muestre la última factura y así sucesivamente
        public static List<BDFactura>? ObtenerFacturas()
        {
            try
            {
                List<BDFactura> facturas = Peta.BD.Fetch<BDFactura>("select * from factura order by codigo desc");
                return facturas;
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Error al obtener las facturas de la base de datos. Error: {ex.Message}",
                    "Error al obtener facturas...", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return null;
            }
        }

        //Obtiene una factura filtrada por código (clave primaria), la devuelve como un objeto de la clase BDFacturas
        public static BDFactura? ObtenerFactura(int codigo)
        {
            try
            {
                BDFactura factura = Peta.BD.First<BDFactura>("select * from factura where codigo = @0", codigo);
                return factura;
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Error al obtener la factura con código [{codigo}] de la base de datos. Error: {ex.Message}",
                    "Error al obtener factura...", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return null;
            }
        }
    }
}

Crear formulario con componentes para acceso a base de datos y tabla de facturas

Añadiremos en el formulario principal de nuestra aplicación C# los siguientes componentes, para acceso al servidor de base de datos y para insertar, mostrar, eliminar y modificar facturas:

Crear formulario con componentes para acceso a base de datos y tabla de facturas

A continuación mostraremos el código fuente de cada botón del formulario. Empezaremos por el botón «Guardar configuración«, que tendrá siguiente código fuente en su evento Click:

        private void BtGuardarConfiguracion_Click(object sender, EventArgs e)
        {
            Config.Guardar("Servidor", txtServidor.Text);
            Config.Guardar("Usuario", txtUsuario.Text);
            Config.Guardar("Contraseña", Cifrar.CifrarAES(txtContraseña.Text, "Encriptad0", "SalT", "MD5", 22, "1234567891234567", 128));
            Config.Guardar("Puerto", txtPuerto.Text);
            Config.Guardar("Base de datos", txtBaseDatos.Text);
        }

El botón «Probar conexión» tendrá el siguiente código fuente en su evento Click:

        private void BtProbarConexion_Click(object sender, EventArgs e)
        {
            try
            {
                if (Peta.BD.Connection.State == System.Data.ConnectionState.Open)
                    MessageBox.Show($"Ya se estableció la conexión con el servidor {txtServidor.Text}.",
                    "Conexión ya establecida...", MessageBoxButtons.OK, MessageBoxIcon.Information);
                else
                {
                    Peta.BD.Connection.Open();
                    MessageBox.Show($"Conexión realizada correctamente al servidor de base de datos {txtServidor.Text}.",
                        "Conexión con servidor de BD...", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Error al conectar a servidor de base de datos: {ex.Message}",
                    "Error de conexión...", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

El botón «Añadir» tendrá el siguiente código C# en su evento Click:

        private void BtInsertarFactura_Click(object sender, EventArgs e)
        {
            //Comprobamos que se hayan introducido los datos básicos de la factura
            bool continuar = txtImporte.Text == "" ? false : true && txtFecha.Text == "" ? false : true && lsCliente.Text == "" ? false : true;

            if (continuar)
            {
                try
                {
                    //Creamos un elemento de la clase BDFactura y le asignamos los valores de los campos
                    BDFactura factura = new()
                    {
                        fecha = txtFecha.Value,
                        cliente = lsCliente.Text,
                        importe = Convert.ToDecimal(txtImporte.Text),
                        observacion = txtObservacion.Text,
                        numero = txtNumero.Text
                    };

                    //Si es una modificación, el TextBox "txtCodigo" tendrá el valor del código (clave primaria) de la factura a modificar
                    //Por lo tanto, lo añadimos al objeto "factura" para la modificación
                    if (txtCodigo.Text != "")
                        factura.Codigo = Convert.ToInt16(txtCodigo.Text);

                    //Si es inserción de factura
                    if (BtInsertarFactura.Text == "Añadir")
                    {
                        //Insertamos la factura en base de datos mediante PetaPoco
                        var resultado = Peta.BD.Insert(factura);
                        MessageBox.Show($"Factura con código [{resultado}] insertada correctamente.",
                            "Factura insertada...", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }

                    //Si es una modificación de una factura existente
                    if (BtInsertarFactura.Text == "Modificar")
                    {
                        var resultado = Peta.BD.Update(factura);
                        if (resultado > 0)
                        {
                            MessageBox.Show($"Factura con número [{factura.numero}] modificada correctamente.",
                                "Factura modificada...", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        }
                        else
                        {
                            MessageBox.Show($"Ha habido algún error al modificar la factura [{factura.numero}].",
                                "Error al modificar factura...", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                    }

                    //Borramos los datos del formulario tras insertar/modificar la factura
                    txtFecha.Value = DateTime.Now;
                    lsCliente.Text = "";
                    txtImporte.Text = "";
                    txtObservacion.Text = "";
                    txtNumero.Text = "";
                    txtCodigo.Text = "";
                    txtFecha.Focus();

                    //Refrescamos el ComboBox de clientes por si se ha añadido un cliente no existente
                    lsCliente.Items.Clear();
                    Pro.ObtenerClientes(lsCliente);

                    //Refrescamos la lista de facturas en el ListView con la nueva factura
                    Pro.ObtenerFacturas(lsFacturas);

                    //Dejamos el botón en modo "Añadir"
                    BtInsertarFactura.Text = "Añadir";
                    GFactura.Text = "Añadir factura";
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"Error al insertar/modificar factura. Error: {ex.Message}",
                        "Error al insertar/modificar factura...", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            else
                MessageBox.Show($"Faltan datos por introducir. Debe indicar la fecha, el cliente y el importe de la factura.",
                    "Faltan datos...", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
        }

El botón «Refrescar» tendrá el siguiente código C#:

        private void BtObtener_Click(object sender, EventArgs e)
        {
            Pro.ObtenerFacturas(lsFacturas);
        }

El botón «Modificar» tendrá el siguiente código:

        private void BtModificar_Click(object sender, EventArgs e)
        {
            if (lsFacturas.SelectedItems.Count >= 1)
            {
                GFactura.Text = "Modificar factura";
                BtInsertarFactura.Text = "Modificar";
                //Obtenemos el código (clave primaria) del registro (factura) elegido por el usuario en el ListView
                int codigo = Convert.ToInt16(lsFacturas.SelectedItems[0].SubItems[0].Text);

                //Buscamos el registro en la tabla factura para obtener los datos y mostrarlos
                var lFacturas = Pro.ObtenerFactura(codigo: codigo);
                if (lFacturas != null)
                {
                    BDFactura factura = lFacturas;
                    txtFecha.Value = factura.fecha;
                    lsCliente.Text = factura.cliente;
                    txtImporte.Text = factura.importe.ToString();
                    txtNumero.Text = factura.numero;
                    txtObservacion.Text = factura.observacion;
                    txtCodigo.Text = codigo.ToString();
                }
                else
                {
                    MessageBox.Show($"No se ha encontrado la factura con código [{codigo}] en la base de datos.",
                        "Factura no encontrada...", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                }
            }
            else
            {
                MessageBox.Show("No ha seleccionado una factura a modificar.",
                    "Selección de factura...", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

Y el botón «Eliminar» tendrá el siguiente código:

        private void btEliminar_Click(object sender, EventArgs e)
        {
            if (lsFacturas.SelectedItems.Count >= 1)
            {
                //Obtenemos el código (clave primaria) del registro (factura) elegido por el usuario en el ListView
                int codigo = Convert.ToInt16(lsFacturas.SelectedItems[0].SubItems[0].Text);

                if (MessageBox.Show($"¿Desea eliminar la factura con código [{codigo}]?", "Eliminar factura...",
                    MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    //Eliminamos la factura en la base de datos con PetaPoco
                    int resultado = Peta.BD.Delete<BDFactura>(codigo);
                    if (resultado > 0)
                    {
                        //Recargamos la lista de facturas en el ListView para que desaparezca la eliminada
                        BtObtener_Click(sender, e);
                        MessageBox.Show($"Factura con código [{codigo}] eliminada correctamente.",
                            "Factura eliminada...", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }
                    else
                    {
                        MessageBox.Show($"La factura con código [{codigo}] no se ha encontrado.",
                            "Factura no encontrada...", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    }
                }
            }
            else
            {
                MessageBox.Show("No ha seleccionado una factura a eliminar.",
                    "Selección de factura...", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

La aplicación C# de ejemplo para insertar, modificar, listar y eliminar facturas con PetaPoco y CSharp

Ejecutaremos la aplicación de gestión de facturas con PetaPoco y C#. Introduciremos los datos de acceso al servidor de base de datos MySQL/MariaDB: servidor (IP o nombre DNS), puerto (habitualmente el 3306), usuario y contraseña de acceso al servidor, BD (nombre de la base de datos o catálogo). Pulsaremos en «Guardar configuración» y ya la tendremos disponible para el resto de inicios de la aplicación. Pulsando en el botón «Probar conexión» la aplicación comprobará si conecta correctamente con el servidor de base de datos. Si conecta mostrará el mensaje:

La aplicación C# de ejemplo para insertar, modificar, listar y eliminar facturas con PetaPoco y CSharp

Si tenemos facturas dadas de alta, la aplicación las mostrará en el ListView «Lista de facturas»:

La aplicación C# de ejemplo para insertar, modificar, listar y eliminar facturas con PetaPoco y CSharp

A partir de ahora, podremos añadir una nueva factura introduciendo los datos básicos en «Añadir factura» y pulsando en «Añadir»:

La aplicación C# de ejemplo para insertar, modificar, listar y eliminar facturas con PetaPoco y CSharp

La factura se añadirá a la base de datos, la aplicación mostrará un mensaje indicando que se ha añadido una nueva factura y el código (clave primaria) asignado:

La aplicación C# de ejemplo para insertar, modificar, listar y eliminar facturas con PetaPoco y CSharp

Y se mostrará en el ListView «Lista de facturas»:

La aplicación C# de ejemplo para insertar, modificar, listar y eliminar facturas con PetaPoco y CSharp

Desde el ListView «Lista de facturas» podremos modificar una factura ya añadida. Para ello, la seleccionaremos y pulsaremos «Modificar»:

La aplicación C# de ejemplo para insertar, modificar, listar y eliminar facturas con PetaPoco y CSharp

Los datos de la factura se cargarán en el cuadro «Modificar factura». Realizaremos la modificación de los datos que deseemos y pulsaremos en el botón «Modificar»:

La aplicación C# de ejemplo para insertar, modificar, listar y eliminar facturas con PetaPoco y CSharp

La aplicación nos indicará que la factura se ha modificado correctamente:

La aplicación C# de ejemplo para insertar, modificar, listar y eliminar facturas con PetaPoco y CSharp

Y mostrará la factura con los datos actualizados en el ListView «Lista de facturas».

También podremos eliminar una factura, seleccionándola y pulsando en «Eliminar». Nos mostrará una confirmación para eliminar, pulsaremos «Sí»:

La aplicación C# de ejemplo para insertar, modificar, listar y eliminar facturas con PetaPoco y CSharp

Nos indicará que la factura ha sido eliminada correctamente y la quitará del ListView:

La aplicación C# de ejemplo para insertar, modificar, listar y eliminar facturas con PetaPoco y CSharp

Descarga del código fuente completo de la aplicación de ejemplo de gestión de facturas en C Sharp

En el siguiente enlace está disponible, de forma totalmente gratuita, el código fuente completo de la aplicación de ejemplo, desarrollada con Visual Studio .Net Community 2022, en C# y PetaPoco: