Guardar datos localmente en app C# sin base de datos

  • Autor Autor AlexMnrs
  • Fecha de inicio Fecha de inicio
El tema de los using la verdad que no lo se por que nunca los he usado mas que para cargar las librerías, pues recordar que se usaba como alias también pero nunca lo llegue a probar.

Si quieres y no tienes inconveniente puedes pasarme el proyecto y le hecho un vistazo y pruebo a ver si doy con el problema, y sera mas fácil y rápido que ir proponiéndote soluciones, que a fin de cuentas estamos a base de prueba y error.
 
Vale, perfecto! Te lo paso por MP en un momento si te parece, lo voy a subir a MEGA.

Enviado!
 
Última edición:
Ok, ahora voy al cine y mientras he dejado descargando el visual studio que no lo tenía instalado. Cuando vuelva le echo un ojo

Enviado desde mi Nexus 4 mediante Tapatalk

- - - Actualizado - - -

Bien, ya lo he solucionado, paso a pegarte el código y te explico los diferentes errores que tenias:

PHP:
private void Form1_Load(object sender, EventArgs e) {
     con = new SQLiteConnection("Data Source=" + mDbPath + ";Version = 3; Compress = True;");
     con.Open();
     SQLiteCommand command = con.CreateCommand();
     command.CommandText = "SELECT name FROM sqlite_master WHERE name='cuenta'";
     var name = command.ExecuteScalar();

     if (name != null) {
          MessageBox.Show("Ya existe");
          return;
     }
     else {                
          command.CommandText = "CREATE TABLE cuenta (rowID INT, user VARCHAR(20), pass VARCHAR(20))";
          command.ExecuteNonQuery();
          MessageBox.Show("Tabla creada");
     }

     con.Close();
}

Cuando creas la conexión tenias puesto el parámetro new=true, lo que hacia que cada vez que ejecutabas el código creara una nueva base de datos por lo tanto siempre que consultas si la tabla cuenta (le puesto ese nombre) existía te daba null.

No lo he mirado pero imagino que el parámetro new solo habrá que usarlo la primera vez que ejecutes la aplicacion para que cree el archivo físico para la base de datos, por lo tanto antes de realizar la conexión deberías comprobar si existe el archivo de la base de datos o no para saber si utilizar el parámetro new o no.

En mi caso para probar ejecute el programa con el parámetro new para que creara la base de datos y después lo borre para que no me la sobrescribiera (por eso no aparece en el texto que he pegado).

Lo siguiente se mantiene igual, compruebas si la consulta de si existe una tabla llamad "cuenta" devuelve null o no para saltar la creación o realizarla.

Por ultimo y muy importante, SIEMPRE cerrar la conexión a la base de datos.

Espero que con esto puedas continuar con tus pruebas. Y si necesitas alguna aclaración o ayuda pues aquí estamos :encouragement:
 
Última edición:
Ok, ahora voy al cine y mientras he dejado descargando el visual studio que no lo tenía instalado. Cuando vuelva le echo un ojo ��

Enviado desde mi Nexus 4 mediante Tapatalk

- - - Actualizado - - -

Bien, ya lo he solucionado, paso a pegarte el código y te explico los diferentes errores que tenias:

PHP:
private void Form1_Load(object sender, EventArgs e) {
     con = new SQLiteConnection("Data Source=" + mDbPath + ";Version = 3; Compress = True;");
     con.Open();
     SQLiteCommand command = con.CreateCommand();
     command.CommandText = "SELECT name FROM sqlite_master WHERE name='cuenta'";
     var name = command.ExecuteScalar();

     if (name != null) {
          MessageBox.Show("Ya existe");
          return;
     }
     else {                
          command.CommandText = "CREATE TABLE cuenta (rowID INT, user VARCHAR(20), pass VARCHAR(20))";
          command.ExecuteNonQuery();
          MessageBox.Show("Tabla creada");
     }

     con.Close();
}

Cuando creas la conexión tenias puesto el parámetro new=true, lo que hacia que cada vez que ejecutabas el código creara una nueva base de datos por lo tanto siempre que consultas si la tabla cuenta (le puesto ese nombre) existía te daba null.

No lo he mirado pero imagino que el parámetro new solo habrá que usarlo la primera vez que ejecutes la aplicacion para que cree el archivo físico para la base de datos, por lo tanto antes de realizar la conexión deberías comprobar si existe el archivo de la base de datos o no para saber si utilizar el parámetro new o no.

En mi caso para probar ejecute el programa con el parámetro new para que creara la base de datos y después lo borre para que no me la sobrescribiera (por eso no aparece en el texto que he pegado).

Lo siguiente se mantiene igual, compruebas si la consulta de si existe una tabla llamad "cuenta" devuelve null o no para saltar la creación o realizarla.

Por ultimo y muy importante, SIEMPRE cerrar la conexión a la base de datos.

Espero que con esto puedas continuar con tus pruebas. Y si necesitas alguna aclaración o ayuda pues aquí estamos :encouragement:

Hostia tío, muchas gracias, de verdad!

Efectivamente con tu código funciona perfectamente, el problema es que si cambio la sentencia SQL por la mía, es decir:

De

PHP:
command.CommandText = "CREATE TABLE cuenta (rowID INT, user VARCHAR(20), pass VARCHAR(20))";

A

PHP:
command.CommandText = "CREATE TABLE contactos (id INT PRIMARY KEY AUTOINCREMENT NOT NULL, nombre VARCHAR(50) NOT NULL, apellido VARCHAR(50), movil VARCHAR(50) NOT NULL, email VARCHAR(50), categoria VARCHAR(50))";

No funciona... Obviamente también he cambiado "cuenta" por "contactos" en la siguiente línea:

PHP:
command.CommandText = "SELECT name FROM sqlite_master WHERE name='contactos'";

Imagino que el problema se encuentra en la sentencia para crear la tabla, pero no veo el error, debo de estar muy ciego... :ambivalence:

SOLUCIONADO. Resulta que en SQLite no existe el AUTOINCREMENT. Cuando declaras una columna como PRIMARY KEY ésta es autoincrementada automáticamente. SQLite incrementa automáticamente los ID.

Más info aquí:
SQLite Frequently Asked Questions
 
Última edición:
Jajajaja a mi también me ha pasado cosas parecidas, en su momento aprendí SQL enfocado en MySQL y cuando empece a trabajar con otros gestores de base de datos me rompí la cabeza por que la nomenclatura de algunas cosas cambiaban.

Aunque no me hace mucha gracia como gestiona eso SQLite, pero supongo que en ausencia del valor de la clave primaria te la autoincrementara y si se la indicas no lo hará.

Y ha sido un placer, cualquier duda que tengas por aquí estamos 😉
 
Yo es que hace unos años estaba metido en programación web, he estado 5 o 6 años completamente alejado de este mundo y ahora lo estoy retomando con C# y Android porque me encantaría poder crear aplicaciones, tanto para ordenadores como para terminales.

El tema anterior ya está solucionado, pero no te creas que dejo de romperme la cabeza...

No sé cómo hacer para editar los contactos, es decir, se supone que en la aplicación tu seleccionarías un contacto, abrirías el formulario de edición, cambiarías algún valor, por ej. el nombre y al pulsar el botón de actualizar se estaría ejecutando una sentencia tal que así:

PHP:
Contactos frmContactos = new Contactos();

string id = frmContactos.dgvDatos.CurrentRow.Cells[0].Value.ToString(); // Aquí creo una variable id para almacenar el rowid, que sería la primera celda, del contacto seleccionado

// Creamos el comando
SQLiteCommand cmd = con.CreateCommand();
cmd.CommandText = "UPDATE contactos SET nombre = @nombreParam, apellido = @apellidoParam, movil =          [MENTION=36130]movil[/MENTION]Param, email =          [MENTION=52771]email[/MENTION]Param, categoria = @categoriaParam WHERE rowid = @id";

cmd.Parameters.Add("@nombreParam", SqlDbType.NVarChar).Value = txtNombre.Text;
cmd.Parameters.Add("@apellidoParam", SqlDbType.NVarChar).Value = txtApellidos.Text;
cmd.Parameters.Add(        [MENTION=36130]movil[/MENTION]Param", SqlDbType.NVarChar).Value = txtMovil.Text;
cmd.Parameters.Add(        [MENTION=52771]email[/MENTION]Param", SqlDbType.NVarChar).Value = txtEmail.Text;
cmd.Parameters.Add("@categoriaParam", SqlDbType.NVarChar).Value = cbCategoria.Text;
cmd.Parameters.Add("@idParam", SqlDbType.NVarChar).Value = id;

El problema es que cuando lo pruebo y voy a modificar cualquier contacto, me tira el siguiente error:

zCXXhqG.png


Por cierto, aparece el BBCode MENTION en varias ocasiones, espero que no te estorbe demasiado a la hora de leer el código. He intentado borrarlo, pero vuelve a aparecer.

EDITO:

He probado a hacerlo de esta manera:

PHP:
DataGridView dgvDatos = ((DataGridView) frmContactos.Controls["dgvDatos"]);
string id = dgvDatos.CurrentRow.Cells[0].Value.ToString();

Y me sigue dando el mismo error...

EDITO:

Lo he solucionado, por fin...

Realmente sigo sin entender por qué lo anterior no funciona, así que si me lo pudieras explicar te lo agradecería 🙁

Lo que he hecho ahora ha sido crear la siguiente variable en el formulario principal:

PHP:
public static Contactos frmContactos;

Luego esto lo he dejado así:

PHP:
public Contactos()
        {
            InitializeComponent();
            frmContactos = this;
        }

Y en el formulario de edición de contacto, la variable id la he dejado de la siguiente manera:

PHP:
string id = Contactos.frmContactos.dgvDatos.CurrentRow.Cells[0].Value.ToString();

Y listo, funciona. Pero repito, no entiendo por qué de la forma anterior no funcionaba y de esta sí... :concern:
 
Última edición:
Si no entendí mal, cuando editas abres un nuevo formulario y ahí es donde ejecutas el primer código que has pegado verdad?

Si es así y viendo el código y el error y como lo has solucionado, diría que estas intentando acceder a un componente de otro formulario, y de entrada te digo que la comunicación de datos entre formularios es poco "especial" y te querrás dar golpes contra la mesa.

Y lo que ha pasado es que al hacerla publica y estática has podido acceder a ella sin problemas.

No lo veo en el código ya que no esta completo pero también hay que tener muy presente el procedimiento de apertura y cierre de la conexión con la base de datos. Para eso lo mejor es prepararse una clase "helper" y crear ahi metodos para las operaciones con la base de datos, conectar, desconectar, consulta nonquery, consulta scalar, etc.
 
Exacto, estaba intentando acceder desde un formulario (el de editar los contactos) a un control de otro formulario (el principal), y yo pensaba que haciendo:

PHP:
Contactos frmContactos = new Contactos();
string id = frmContactos.dgvDatos.CurrentRow.Cells[0].Value.ToString();

Era suficiente, pero no sé por qué, no funciona. No sé si me estaré confundiendo con otro lenguaje, no tengo ni idea, pero juraría que se hacía así... :ambivalence:

Lo de la base de datos lo tengo pensado, pero no sé ni por donde empezar si te digo la verdad, creo que eso es un poco más avanzado (?), pero le echaré un vistazo a ver que puedo hacer. Por cierto he descubierto que si abres la conexión a la base de datos con un using, no hace falta cerrarla luego porque se cierra automáticamente.

- - - Actualizado - - -

Nada, cuando pensaba que ya estaba prácticamente todo funcionando sin ningún problema, me ha dado por recompilar el instalador para volver a instalar la aplicación actualizada y me encuentro con esto...

pakFLuI.png


Cierro el mensaje, cierro la aplicación porque se ejecuta pero no puedo añadir contactos ni nada de nada, la vuelvo a abrir, y ahora me aparece otro error distinto al de antes:

Pf5tiYC.png


Este es todo el error completo:

Consulte el final de este mensaje para obtener más detalles sobre cómo invocar a la depuración
Just-In-Time (JIT) en lugar de a este cuadro de diálogo.

************** Texto de la excepción **************
Finisar.SQLite.SQLiteException: unable to open database file
en Finisar.SQLite.sqlite3.Throw()
en Finisar.SQLite.sqlite3.open(String filename)
en Finisar.SQLite.SQLiteConnection.Open()
en Contactos.Utilidades.CrearBD()
en Contactos.Contactos.Contactos_Load(Object sender, EventArgs e)
en System.Windows.Forms.Form.OnLoad(EventArgs e)
en System.Windows.Forms.Form.OnCreateControl()
en System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
en System.Windows.Forms.Control.CreateControl()
en System.Windows.Forms.Control.WmShowWindow(Message& m)
en System.Windows.Forms.Control.WndProc(Message& m)
en System.Windows.Forms.ScrollableControl.WndProc(Message& m)
en System.Windows.Forms.Form.WmShowWindow(Message& m)
en System.Windows.Forms.Form.WndProc(Message& m)
en System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
en System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
en System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)


************** Ensamblados cargados **************
mscorlib
Versión del ensamblado: 4.0.0.0
Versión Win32: 4.6.1076.0 built by: NETFXREL3STAGE
Código base: file:///C:/Windows/Microsoft.NET/Framework/v4.0.30319/mscorlib.dll
----------------------------------------
Contactos
Versión del ensamblado: 1.0.0.0
Versión Win32: 1.0.0.0
Código base: file:///C:/Program%20Files/Alex%20Monr%C3%A1s/Contactos/Contactos.exe
----------------------------------------
System.Windows.Forms
Versión del ensamblado: 4.0.0.0
Versión Win32: 4.6.1055.0 built by: NETFXREL2
Código base: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Windows.Forms/v4.0_4.0.0.0__b77a5c561934e089/System.Windows.Forms.dll
----------------------------------------
System
Versión del ensamblado: 4.0.0.0
Versión Win32: 4.6.1075.0 built by: NETFXREL3STAGE
Código base: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System/v4.0_4.0.0.0__b77a5c561934e089/System.dll
----------------------------------------
System.Drawing
Versión del ensamblado: 4.0.0.0
Versión Win32: 4.6.1068.2 built by: NETFXREL3STAGE
Código base: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Drawing/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Drawing.dll
----------------------------------------
System.Configuration
Versión del ensamblado: 4.0.0.0
Versión Win32: 4.6.1055.0 built by: NETFXREL2
Código base: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Configuration/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Configuration.dll
----------------------------------------
System.Core
Versión del ensamblado: 4.0.0.0
Versión Win32: 4.6.1055.0 built by: NETFXREL2
Código base: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Core/v4.0_4.0.0.0__b77a5c561934e089/System.Core.dll
----------------------------------------
System.Xml
Versión del ensamblado: 4.0.0.0
Versión Win32: 4.6.1067.0 built by: NETFXREL3STAGE
Código base: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Xml/v4.0_4.0.0.0__b77a5c561934e089/System.Xml.dll
----------------------------------------
System.Windows.Forms.resources
Versión del ensamblado: 4.0.0.0
Versión Win32: 4.6.1055.0 built by: NETFXREL2
Código base: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Windows.Forms.resources/v4.0_4.0.0.0_es_b77a5c561934e089/System.Windows.Forms.resources.dll
----------------------------------------
SQLite.NET
Versión del ensamblado: 0.21.1869.3794
Versión Win32: 0.21.1869.3794
Código base: file:///C:/Program%20Files/Alex%20Monr%C3%A1s/Contactos/SQLite.NET.DLL
----------------------------------------
System.Data
Versión del ensamblado: 4.0.0.0
Versión Win32: 4.6.1082.0 built by: NETFXREL3STAGE
Código base: file:///C:/Windows/Microsoft.Net/assembly/GAC_32/System.Data/v4.0_4.0.0.0__b77a5c561934e089/System.Data.dll
----------------------------------------
mscorlib.resources
Versión del ensamblado: 4.0.0.0
Versión Win32: 4.6.1055.0 built by: NETFXREL2
Código base: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/mscorlib.resources/v4.0_4.0.0.0_es_b77a5c561934e089/mscorlib.resources.dll
----------------------------------------

************** Depuración JIT **************
Para habilitar la depuración Just In Time (JIT), el archivo de configuración de esta
aplicación o equipo (machine.config) debe tener el
valor jitDebugging establecido en la sección system.windows.forms.
La aplicación también se debe compilar con la depuración
habilitada

Por ejemplo:

<configuration>
<system.windows.forms jitDebugging="true" />
</configuration>

Cuando esté habilitada la depuración JIT, cualquier excepción no controlada
se enviará al depurador JIT registrado en el equipo
en lugar de controlarlo mediante el cuadro de diálogo.

He cambiado la plataforma de destino del proyecto de .NET Framework 4.5.2 a la 4.5, pero sigue exactamente igual.

Sin embargo en Visual Studio va perfecto. A ver que es lo que pasa ahora... :/

EDITO:

No sé si tendrá algo que ver, pero a lo mejor el problema es la ruta de la base de datos?

PHP:
public static string mDbPath = Application.StartupPath + "\\" + "contactos.sqlite";

Quizás el que esté localizada en el directorio de la aplicación, es decir, en ProgramFiles, ocasiona algún tipo de problema a la hora de abrir/escribir en la base de datos. Me gustaría ubicarla en AppData, pero no sé cómo hacerlo.

He intentado hacer algo así, en este caso para intentar guardarla en Documentos:

PHP:
private static string databaseFilePath;
string docs = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
databaseFilePath = Path.Combine(docs, "contactos.sqlite");

Pero, por si fuera poco, otro problema más que me frena:

KsCi4ON.png
 
Última edición:
La navegación entre formularios en visual basic si es mas sencilla pero en C# tiene sus peculiaridades y yo lo que hacia era que cuando cargaba un nuevo formulario le enviaba a este los datos que necesitaba.

Otra opción es en vez de lanzar un nuevo formulario trabajar con paneles, que por ejemplo para este caso lo veo mas acertado ya que hablamos de una pequeña ventana para editar los datos de contacto.

Como te comente nunca he usado el using así que no sabría decir si es verdad que cierra la conexión de la base de datos... pero yo lo buscaría para asegurarme no vaya ser que luego vengan las sorpresas.

En lo que respecta a la clase helper que comentaba te muestro un ejemplo de una que me hice para una app de sql server:

Insertar CODE, HTML o PHP:
using System;using System.Data.SqlClient;
using System.Data;
using System.Collections;


namespace Rol
{
    class ConexionBD
    {
        //Variables Globales
        String cadena = "Data Source=(LocalDB)\\MSSQLLocalDB;AttachDbFilename=\"C:\\Users\\Ivan\\Documents\\Visual Studio 2015\\Projects\\Rol\\Rol\\Recursos\\Rol.mdf\";Integrated Security=True;Connect Timeout=30";
        SqlConnection con = new SqlConnection();
        SqlCommand orden = new SqlCommand();
        SqlDataReader reader;


        //Constructor
        public ConexionBD() { con.ConnectionString = cadena; }


        //Consultas NonQuery
        public void consultaNonQuery(String consulta)
        {
            con.Open();
            orden.CommandText = consulta + "";
            orden.CommandType = CommandType.Text;
            orden.Connection = con;
            orden.ExecuteNonQuery();
            con.Close();
        }


        //Consultas Scalar
        public int consultaScalar(String consulta)
        {
            con.Open();
            orden.CommandText = consulta + "";
            orden.CommandType = CommandType.Text;
            orden.Connection = con;
            int datos = (int)orden.ExecuteScalar();
            con.Close();


            return datos;
        }


        //Consulta Query estandar
        public ArrayList consultaQuery(String consulta)
        {
            ArrayList datos = new ArrayList();


            con.Open();
            orden.CommandText = consulta + "";
            orden.CommandType = CommandType.Text;
            orden.Connection = con;
            reader = orden.ExecuteReader();


            while (reader.Read())
            {
                datos.Add(reader.GetString(0));
            }


            con.Close();
            return datos;
        }
    }
}

Y luego puedes crearte algunos métodos mas para consultas mas concretas que uses muchos.

Respecto a los problemas al recompilar el instalador, pégate aquí el código final del load del form para que le eche un ojo.
 
Última edición:
Miraré todo eso que me has dicho, tanto los paneles como la clase helper que me has dejado de ejemplo, que te doy las gracias por cierto.

Ya me está sacando de quicio demasiado este último problema. Así como con los anteriores, más o menos, íbamos hablando y orientándonos un poco sobre lo que podía estar pasando, en este caso no tengo ni la más remota idea. Sigo pensando que podría ser por la ubicación de la BD, pero es que tampoco consigo ubicarla en AppData que es donde se supone debería de estar.

En fin, aquí tienes el código final del formulario principal:

PHP:
using System;
using System.Data;
using System.Windows.Forms;
using Finisar.SQLite;

namespace Contactos
{
    public partial class Contactos : Form
    {
        public static Contactos frmContactos;

        public Contactos()
        {
            InitializeComponent();
            frmContactos = this;
        }

        private void Contactos_Load(object sender, EventArgs e)
        {
            Utilidades.CrearBD();
            Display();
        }

        private void btnSalir_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void btnAñadirContacto_Click(object sender, EventArgs e)
        {
            AñadirContacto frmAñadirContacto = new AñadirContacto();
            frmAñadirContacto.Show();
            frmAñadirContacto.FormClosed += new FormClosedEventHandler(frmAñadirContacto_FormClosed);
        }

        private void frmAñadirContacto_FormClosed(object sender, FormClosedEventArgs e)
        {
            Display();
        }

        private void btnEliminar_Click(object sender, EventArgs e)
        {
            BorrarContacto();
        }

        private void btnEditar_Click(object sender, EventArgs e)
        {
            AñadirContacto frmEditarContacto = new AñadirContacto();

            // Cargamos los datos del DataGridView en el formulario
            frmEditarContacto.txtNombre.Text = dgvDatos.CurrentRow.Cells[1].Value.ToString();
            frmEditarContacto.txtApellidos.Text = dgvDatos.CurrentRow.Cells[2].Value.ToString();
            frmEditarContacto.txtMovil.Text = dgvDatos.CurrentRow.Cells[3].Value.ToString();
            frmEditarContacto.txtEmail.Text = dgvDatos.CurrentRow.Cells[4].Value.ToString();
            frmEditarContacto.cbCategoria.Text = dgvDatos.CurrentRow.Cells[5].Value.ToString();

            frmEditarContacto.Text = "Editar contacto";
            frmEditarContacto.btnEditar.Enabled = true;
            frmEditarContacto.btnAceptar.Enabled = false;
            frmEditarContacto.Show();
            frmEditarContacto.FormClosed += new FormClosedEventHandler(frmEditarContacto_FormClosed);
        }

        private void frmEditarContacto_FormClosed(object sender, FormClosedEventArgs e)
        {
            Display();
        }

        public void Display()
        {
            try
            {
                using (SQLiteConnection con = new SQLiteConnection(Utilidades.conString))
                {
                    // Abrimos la conexión
                    con.Open();

                    // Creamos un objecto DataTable para hacer referencia a la información retornada por la consulta
                    DataTable datos = new DataTable();

                    // Creamos el comando
                    SQLiteCommand cmd = con.CreateCommand();
                    cmd.CommandText = "SELECT rowid, * FROM contactos;";

                    // Creamos un objeto adapter con un constructor que recibe como parámetro el comando asociado
                    SQLiteDataAdapter da = new SQLiteDataAdapter(cmd);

                    // Usamos el método Fill() que deposita de forma ordenada los registros en nuestra tabla
                    da.Fill(datos);

                    dgvDatos.Rows.Clear();
                    foreach (DataRow item in datos.Rows)
                    {
                        int n = dgvDatos.Rows.Add();
                        dgvDatos.Rows[n].Cells[0].Value = item[0].ToString();
                        dgvDatos.Rows[n].Cells[1].Value = item[1].ToString();
                        dgvDatos.Rows[n].Cells[2].Value = item[2].ToString();
                        dgvDatos.Rows[n].Cells[3].Value = item[3].ToString();
                        dgvDatos.Rows[n].Cells[4].Value = item[4].ToString();
                        dgvDatos.Rows[n].Cells[5].Value = item[5].ToString();
                    }
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show("Ha ocurrido un error: " + ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void BorrarContacto()
        {
            DialogResult myResult;
            myResult = MessageBox.Show("Está seguro de que desea eliminar a " + dgvDatos.CurrentRow.Cells[1].Value.ToString() + "?", "Eliminar contacto", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);

            if (myResult == DialogResult.OK)
            {
                using (SQLiteConnection con = new SQLiteConnection(Utilidades.conString))
                {
                    // Abrimos la conexión
                    con.Open();

                    // Creamos el comando
                    SQLiteCommand cmd = con.CreateCommand();
                    cmd.CommandText = "DELETE FROM Contactos WHERE rowid = " + dgvDatos.CurrentRow.Cells[0].Value.ToString();

                    // Ejecutamos el comando
                    cmd.ExecuteNonQuery();

                    // Actualizamos la información del DataGridView
                    Display();
                }
            }
            else
            {
                return;
            }
        }
    }
}

Te dejo también el código de la clase Utilidades por si las dudas:

PHP:
using Finisar.SQLite;
using System.IO;
using System.Windows.Forms;

namespace Contactos
{
    class Utilidades
    {
        //private static string databaseFilePath;
        //string docs = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
        //databaseFilePath = Path.Combine(docs, "contactos.sqlite"); // FIX: No reconoce el Path.Combine. Averiguar como crear BD en AppData.

        public static string mDbPath = Application.StartupPath + "\\" + "contactos.sqlite";
        public static string conString = "Data Source=" + mDbPath + ";Version = 3;Compress = True;";

        public static void CrearBD()
        {
            // Comprobamos si la BD existe o hay que crearla
            if (!File.Exists(mDbPath))
            {
                SQLiteConnection con = new SQLiteConnection("Data Source=" + mDbPath + ";New = True;Version = 3;Compress = True;");
                con.Open();
                SQLiteCommand cmd = con.CreateCommand();
                cmd.CommandText = "SELECT name FROM sqlite_master WHERE name='contactos'";
                var name = cmd.ExecuteScalar();

                if (name != null)
                {
                    return;
                }
                else
                {
                    // Definimos la estructura
                    cmd.CommandText = @"CREATE TABLE
                contactos (nombre VARCHAR(50) NOT NULL, apellido VARCHAR(50), movil VARCHAR(50) NOT NULL, email VARCHAR(50), categoria VARCHAR(50))";
                    cmd.ExecuteNonQuery();
                }

                con.Close();
            }
        }

        public static void LimpiarCampos(Control form)
        {
            foreach (Control ctrl in form.Controls)
            {
                if (ctrl is TextBox)
                {
                    (ctrl as TextBox).Clear();
                }

                if (ctrl is ComboBox)
                {
                    (ctrl as ComboBox).Text = null;
                }
            }
        }

    }
}

Espero que no te cueste mucho entender el código. He intentado dejarlo lo más "limpio" y "legible" posible dentro de mis posibilidades... 🙄
 
Borra el archivo de la base de datos fisico del proyecto de visual y prueba a ejecutarlo para descartar que no te este dando problemas el "if (!File.Exists(mDbPath))"

Y no entiendo muy bien la ruta del archivo. Ahora tienes esto:

public static string mDbPath = Application.StartupPath + "" + "contactos.sqlite"

Y antes tenias esto:

string mDbPath = Application.StartupPath + "/Contactos.db";

No recuerdo mucho de las rutas pues era un tema bastante puñetero, pero me llama la atencion el cambio de la orientación de la barra (que lo mismo no tiene nada que ver).

Igualmente asegúrate que cuando ejecutes el ejecutable no tengas abierto el proyecto de visual o la base de datos desde un gestor, ya que si detecta que esta abierto por otro programa te lanza error.
 
Borra el archivo de la base de datos fisico del proyecto de visual y prueba a ejecutarlo para descartar que no te este dando problemas el "if (!File.Exists(mDbPath))"

Y no entiendo muy bien la ruta del archivo. Ahora tienes esto:

public static string mDbPath = Application.StartupPath + "" + "contactos.sqlite"

Y antes tenias esto:

string mDbPath = Application.StartupPath + "/Contactos.db";

No recuerdo mucho de las rutas pues era un tema bastante puñetero, pero me llama la atencion el cambio de la orientación de la barra (que lo mismo no tiene nada que ver).

Igualmente asegúrate que cuando ejecutes el ejecutable no tengas abierto el proyecto de visual o la base de datos desde un gestor, ya que si detecta que esta abierto por otro programa te lanza error.

Si te digo la verdad, creo que no sabría explicartelo bien. La cosa es que cuando lo tenía con la barra normal, es decir así /, en el proyecto se ejecuta bien y funcionaba, pero al momento instalar la aplicación en el sistema una vez ya compilada y todo, no cargaba la base de datos porque la ruta quedaba algo así:

Insertar CODE, HTML o PHP:
C:\Program Files\Contactos/database.sqlite

Entonces la aplicación no funcionaba obviamente porque no cargaba ni creaba ni nada la base de datos.

Ahí fue cuando me acordé de que la contrabarra se representa en C# con dos iguales y probé y funcionó. Utilicé un MessageBox para imprimir la ruta en pantalla y efectivamente ya estaba bien y funcionaba.

Mañana probaré de quitar el if File.Exists y lo que dices de no tener abierto el proyecto o la BD en un gestor, porque no recuerdo si eso lo hice o no. Si el problema estuviese en el if, ya no sé qué hacer para crear la base de datos sólo no exista, porque si dejo siempre puesto el parámetro new=true; me la sobreescribe y se borran todos los datos, claro.

Espero que no sea eso...

Un saludo!

Enviado desde mi SM-G925F mediante Tapatalk

- - - Actualizado - - -

Bueno, te comento.

He hecho varias comprobaciones y estoy ya 100% seguro de que la base de datos no puede estar en Archivo de programas porque no se puede escribir en ella. No tiene el atributo de Sólo lectura, pero seguro que es eso y te explico por qué...

El proyecto lo tengo ubicado en D:, mi disco duro secundario. Al probar la aplicación desde Visual Studio funciona perfectamente, se crea la base de datos, las tablas, todo bien.

Sin embargo, cuando instalas la aplicación en el sistema, es decir, la ubicación ya no es mi disco duro secundario, sino que es el C:, ahí es cuando no funciona. Entonces las dos comprobaciones que he hecho han sido las siguientes.

Primero he creado un método muy simple para comprobar que la BD se crea y lo he metido en el evento click de cualquiera de los botones. Al ejecutar la aplicación y darle al botón me lanza un True, o sea que la BD se crea y existe.

La segunda comprobación ha sido abrir la BD de la aplicación ya instalada, en el gestor de SQLite de Firefox y efectivamente el problema es que no se crea la tabla, no existe la tabla contactos, a diferencia de la que hay en la carpeta del proyecto que sí que la crea sin problemas.

Conclusión: el código no está mal, lo único que hay que cambiar es la ruta y poner que la BD esté en AppData y no en la carpeta de la aplicación porque ahí sí que podrá crear la tabla sin problema. La pregunta es CÓMO :grumpy: he leído mucho sobre eso y he visto ejemplos y casi siempre utilizan el método Path.Combine() que a mí no me funciona, entonces no sé cómo hacerlo...
 
Osea te crea la base de datos y por tanto te devuelve true, pero no te crea la tablas?
 
Al final he conseguido solucionarlo, este es el código final de la clase Utilidades:

PHP:
using Finisar.SQLite;
using System;
using System.IO;
using System.Windows.Forms;

namespace Contactos
{
    class Utilidades
    {
        public static string appData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
        public static string databaseFilePath = Path.Combine(appData, "contactos.sqlite");

        //public static string mDbPath = Application.StartupPath + "\\" + "contactos.sqlite";
        public static string conString = "Data Source=" + databaseFilePath + ";Version = 3;Compress = True;";

        public static void CrearBD()
        {
            // Comprobamos si la BD existe o hay que crearla
            if (!File.Exists(databaseFilePath))
            {
                SQLiteConnection con = new SQLiteConnection("Data Source=" + databaseFilePath + ";New = True;Version = 3;Compress = True;");
                con.Open();
                SQLiteCommand cmd = con.CreateCommand();
                cmd.CommandText = "SELECT name FROM sqlite_master WHERE name='contactos'";
                var name = cmd.ExecuteScalar();

                if (name != null)
                {
                    return;
                }
                else
                {
                    // Definimos la estructura
                    cmd.CommandText = @"CREATE TABLE
                contactos (nombre VARCHAR(50) NOT NULL, apellido VARCHAR(50), movil VARCHAR(50) NOT NULL, email VARCHAR(50), categoria VARCHAR(50))";
                    cmd.ExecuteNonQuery();
                }

                con.Close();
            }
        }

El problema por lo que el método Path.Combine() no me estaba funcionando era por haber declarado la variable databaseFilePath dos veces o algo así... una tontería. Fíjate, antes tenía esto:

PHP:
private static string databaseFilePath;
string docs = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
databaseFilePath = Path.Combine(docs, "contactos.sqlite"); // FIX: No reconoce el Path.Combine. Averiguar como crear BD en AppData.

Eso sí, esa clase Utilidades no sé qué tiene que a todo me hace ponerle static delante, si no no funciona bien:

EjL1OvN.png


Pero bueno ya está solucionado. Ahora sólo me queda crear un if comprobando si el directorio Contactos !existe en AppData y de ser así, crearlo. Porque por el momento me está creando la BD directamente en AppData\Local suelto, y quiero que esté en AppData\Local\Contactos\, pero bueno todo bien ya!
 
El tema de las rutas como comento es muy puñetero. Recuerdo una app que hice en java y que también le embebí la base de datos, y cuando me puse con el tema de la ruta de la base de datos al indicarle que la guardara donde ejecuta la app, desde el netbeans genial, me la creaba en la carpeta debug donde generaba el compilado, pero ahora cuando creaba el "ejecutable" no había manera, no paraba de fallarme por que no tenia permisos.

Lo mejor fue cuando lo cambie de ruta y si usaba la aplicacion desde c:/ sin problema, ahora como la usara en otro sitio la base de datos me la creaba en c:/windows/win32. No recuerdo como lo solucione al final pero menudo dolor de cabeza....

Y lo del static creo que es por que tienes que importar la clase con using para que estén disponibles los métodos, aunque no estoy seguro, no recuerdo muy bien como era eso en C#.
 
Hay que tener mucha paciencia cuando empiezas a programar por lo que veo... y yo tengo poca jajaja

Lo del static creo que es porque estoy inicializando todo fuera, o sea directamente en la clase, no en un constructor o en un método y para hacerlo así sólo puedo utilizar literales o miembros estáticos... pero eso ya lo miraré. Ahora que he solucionado todo esto quiero centrarme en Android, que también lo estoy tocando y casi que me gusta más hacer apps móviles que apps de escritorio, no sé por qué. Android Studio es una pasada como IDE 😛4:

Bueno tío, mil gracias por acompañarme en estos días malos que he tenido de romperme la cabeza, has aguantado hasta el final y lo valoro muchísimo, te lo agradezco mogollón!! :love_heart:
 
El que estén fuera del constructor o métodos no tendría por que influir ya que esas variables se consideran globales a la clase. Es mas incluso poniéndolas como privada deberías poder acceder a ellas desde dentro de la propia clase.

Ahora para acceder a ellas desde fuera como te comento creo que tienes que importar primero la clase, aunque tendrías que probarlo pero no estoy del todo seguro, pues en java y android es así pero no recuerdo si C# también.

Y por supuesto android a mi parecer es mas bonito que escritorio, pero a la vez lo veo mas limitado e infinitamente mas difícil.

Aquí por que hay muchos usando frameworks javascript para hacer apps que te lo dan todo medio hecho y ya parece que hacer una app es un paseo, pero hacer una buena app en android nativo es un buen dolor de cabeza. Cuando ves la que lías para montarte una lista cuando en visual solo arrastras el componente y le metes los datos te dan ganas de pegarte un tiro xD

Eso si, cuando te desenvuelves en android no querrás volver a escritorio. Vamos yo ahora mismo solo toco android y no lo cambio 🙄

Y no hay nada que agradecer :encouragement: Para cualquier cosa aquí estamos
 
Atrás
Arriba