none
the connection current state is open RRS feed

  • Pregunta

  • Hola a todos, necesito ayuda!

    Mi problema es que necesito abrir una conexion dentro de un while que ya tiene una conexion abierta.

    No se como controlarlo.

    Desde ya muchas gracias!

    MySqlConnectionStringBuilder Build = new MySqlConnectionStringBuilder();
    Build.Server = "localhost";
    Build.UserID = "user";
    Build.Password = "pass";
    Build.Database = "database";
    MySqlConnection conn = new MySqlConnection(Build.ToString());
    conn.Open();
    var cmd = conn.CreateCommand();
    cmd.CommandText = "Select dato1, dato2, dato3 from tabla1";
    MySqlDataReader Registros = cmd.ExecuteReader();
    while (Registros.Read())
    {
    	if (Registros.GetString(2).Contains("1"))
    	{
    		cmd.CommandText = "insert into tabla2  (dato1, dato2, dato3) values '" +1+"','"+2+"','"+3+"'";
    		cmd.ExecuteNonQuery();
    	}
    }
    conn.Close();

    • Cambiado Sergio Parra sábado, 13 de agosto de 2016 19:06 pregunta de acceso a datos
    miércoles, 10 de agosto de 2016 5:10

Todas las respuestas

  • Está bien como lo tienes: es perfectamente válido abrir la conexión antes de entrar en el bucle, usarla múltiples veces dentro del bucle, y luego cerrarla cuando se termine.

    Si necesitas OTRA conexión dentro del bucle (como ocurre en este caso, ya que quieres usar un command sobre la misma conexión que ya está abierta), puedes simplemente hacer el Open de esta segunda conexión, usarla, y luego un Close. No hay problema en repetir muchas veces el Open y Close porque gracias al Pool de conexiones estas dos operaciones son muy rápidas (ya que la conexión no se abre y cierra de verdad, sino que se toma del pool y se devuelve al pool). O bien, en el caso concreto del código que has puesto, puedes abrir una segunda conexión fuera del bucle, usarla en el command que está dentro del bucle (que debería ser distinto del command que usas para el DataReader), y luego cerrarla cuando salgas del bucle.

    miércoles, 10 de agosto de 2016 6:24
  • Muchas gracias por tu ayuda!

    si entendi bien el codigo quedaria asi?

    dos conexiones y dos comandos...

    MySqlConnectionStringBuilder Build = new MySqlConnectionStringBuilder();
    Build.Server = "localhost";
    Build.UserID = "user";
    Build.Password = "pass";
    Build.Database = "database";
    MySqlConnection conn = new MySqlConnection(Build.ToString());
    MySqlConnection conn2 = new MySqlConnection(Build.ToString());
    conn.Open();
    var cmd = conn.CreateCommand();
    var cmd2 = conn.CreateCommand();
    cmd.CommandText = "Select dato1, dato2, dato3 from tabla1";
    MySqlDataReader Registros = cmd.ExecuteReader();
    while (Registros.Read())
    {
    	if (Registros.GetString(2).Contains("1"))
    	{
    		conn2.Open();
    		cmd2.CommandText = "insert into tabla2  (dato1, dato2, dato3) values '" +1+"','"+2+"','"+3+"'";
    		cmd2.ExecuteNonQuery();
    		conn2.Close();
    	}
    }
    conn.Close();

    miércoles, 10 de agosto de 2016 6:51
  • hola

    hay algunos detales en el codigo

    - no te va a dejar mantener un reader y realizar insert al mismo tiempo, tienes que usar un objeto desconectado como ser un datatable

    - cuando armas el insert no veo que uses el reader para asignar los valores

    El codigo deberia ser algo cmo esto

    MySqlConnectionStringBuilder Build = new MySqlConnectionStringBuilder();
    Build.Server = "localhost";
    Build.UserID = "user";
    Build.Password = "pass";
    Build.Database = "database";
    
    MySqlConnection conn = new MySqlConnection(Build.ToString());
    conn.Open();
    
    string query = "Select dato1, dato2, dato3 from tabla1";
    var cmd = new MySqlCommand(query,conn);
    var da = new MySqlDataAdapter(cmd);
    DataTable dt = new DataTable();
    da.Fill(dt);
    
    string queryInsert = "insert into tabla2  (dato1, dato2, dato3) values (?p1, ?p2, ?p3)";
    var cmd2 = new MySqlCommand(queryInsert,conn);
    
    foreach(var row in dt.Rows)
    {
    	if (row["dato2"].ToString().Contains("1"))
    	{
    		cmd2.Parameters.Clear();
    		cmd2.Parameters.AddWithValue("?p1", row["dato1"]);
    		cmd2.Parameters.AddWithValue("?p2", row["dato2"]);
    		cmd2.Parameters.AddWithValue("?p3", row["dato3"]);
    		cmd2.ExecuteNonQuery();
    	}
    }
    
    conn.Close();

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina


    miércoles, 10 de agosto de 2016 9:49
  • si entendi bien el codigo quedaria asi?

    Sí, más o menos quedaría así. Pero nótese que no es necesario abrir y cerrar el conn2 a cada iteración del bucle; te bastaría con abrirlo al principio y cerrarlo al final, igual que haces con el conn. La única razón de usar una segunda conexión en lugar de la primera es que la primera no te la deja usar mientras el Reader esté abierto. Pero por lo demás, basta con que abras una vez la conexión y crees una vez el command (que por cierto, tienes que crearlo desde el conn2, no desde el conn) y luego a cada iteración le cambies el commandtext.

    Por cierto, la sentencia sql que usas es muy rara, ya que es siempre la misma en todas las iteraciones y no aplica ningún dato de los que vas leyendo en el bucle.

    miércoles, 10 de agosto de 2016 18:02
  • si entendi bien el codigo quedaria asi?

    Sí, más o menos quedaría así. Pero nótese que no es necesario abrir y cerrar el conn2 a cada iteración del bucle; te bastaría con abrirlo al principio y cerrarlo al final, igual que haces con el conn. La única razón de usar una segunda conexión en lugar de la primera es que la primera no te la deja usar mientras el Reader esté abierto. Pero por lo demás, basta con que abras una vez la conexión y crees una vez el command (que por cierto, tienes que crearlo desde el conn2, no desde el conn) y luego a cada iteración le cambies el commandtext.

    Por cierto, la sentencia sql que usas es muy rara, ya que es siempre la misma en todas las iteraciones y no aplica ningún dato de los que vas leyendo en el bucle.

    Si... tienes Razón! el command debio ser del conn2, (error de tipeo) con respecto a la sentencia la reduje muchisimo solo para el ejemplo, ya que mi codigo es mas amplio y está separado en otras clases. Por ahora me esta funcionando.... me queda la duda de estar usando una buena logica... he visto en internet la recomendacion de crear las conexiones dentro de un using... Pero aun no he logrado entender la logica.

    Muchas gracias por tu tiempo.

    miércoles, 10 de agosto de 2016 19:18
  • >>me queda la duda de estar usando una buena logica

    no es correcta la logica ni tampoco puedes abrir dos conexiones concurrentes a la base de datos

    en MySql no tienes soporte para MARS

    ademas porque definir dos objeto de conexion si el connection string es el mismo, eso es incorrecto

    sigo planteando que debes usar un objeto desconectado para iterar en el loop, de esta forma no necesitas mantener la conexion a la db activa y puedes actualizar mientras iteras

    >>he visto en internet la recomendacion de crear las conexiones dentro de un using

    si es correcto, podrias usar

    using(MySqlConnection conn = new MySqlConnection(Build.ToString()))
    {
    	conn.Open();
    	
    	//resto del codigo
    
    }

    pero el mysqlcommand es uno solo si vas a connectarte a la misma db

    ademas en el codigo debes usar parametros para pasar los valores que iteras en el insert

    analzia el ejemplo que planteo para entender lo que trato de explicar

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    jueves, 11 de agosto de 2016 11:04
  • Leandro, muchas gracias por tu tiempo.

    Me gustaria saber el "por que" la recomendación del using. (dentro del using se debe cerrar la conexion) leí que es una conexion desechable (no me queda claro).

    Por otro lado tratando de entender bien la logica de esto.

    Cada vez que necesite sacar, actualizar o modificar datos de una tabla debo abrir y cerrar la conexión?

    como lo estoy manejando ahora es por clases.

    Ejemplo:

            public void actualizaFrozen(string path, string file)
            {
                // Leer archivo XML
                XmlDocument xDoc = new XmlDocument();
                xDoc.Load(path + file);
    
                // Extraemos el pod id del archivo XML que se esta leyendo
                string podId = xDoc.GetElementsByTagName("PodId").Item(0).InnerText;
                string fecha = xDoc.GetElementsByTagName("Timestamp").Item(0).InnerText;
                string lectura = xDoc.GetElementsByTagName("Value").Item(2).InnerText;
    
                // Conexion a la base de datos
                var conn2 = Util.Util.OpenConnection("reportstarbeat");
                var cmd2 = conn2.CreateCommand();
                //Debemos limpiar la fecha para insertarla en la base de datos
                fecha = fecha.Substring(0, 10);
                // Crea sentencia
                cmd2.CommandText = "UPDATE `reportstarbeat`.`facturaregulados` SET `Fecha`= '"+fecha+"', `LecturaFrozen`= '"+lectura+"' WHERE `PodId`= '"+podId+"'";
                //Ejecutamos la sentencia
                cmd2.ExecuteNonQuery();
                conn2.Close();
            }


    Cristian

    jueves, 11 de agosto de 2016 19:27
  • Me gustaria saber el "por que" la recomendación del using.

    Normalmente bastaría con poner conexion.Open(); sentencias; conexion.Close(). Pero imagínate que en esas sentencias hay muchas líneas de código, y un día alguien modifica ese código y, por ejemplo, añade algo así como if (condicion) return;.

    ¿Qué pasaría? pues que "de vez en cuando", cuando se cumpla la condición, la conexión se quedaría sin cerrar. Al principio no pasaría nada, simplemente se gastaría una conexión del pool. Pero con el tiempo, según se va usando la aplicación, se irán consumiendo más y más conexiones hasta que llegue un momento en que se produzca un error al abrir una conexión en OTRO sitio. Este es un problema dificilísimo de resolver en una aplicación grande, porque el error te sale en un sitio distinto, y porque no es repetible, dado que se produce aleatoriamente dependiendo de cuántas veces se haya cumplido la condición y se haya salido del bloque sin cerrar la conexión.

    Se resuelve con el bloque "using", porque éste garantiza que se cierra la conexión siempre que se abandone el bloque de código, incluso aunque se abandone desde el medio con un return, o con una excepción.

    viernes, 12 de agosto de 2016 6:41