none
Error Al hacer uso Transacciones en Visual Basic.NET RRS feed

  • Pregunta

  • Bueno, mi problema es que me sale un error al usar el programa, especificamente el boton, al que le he puesto la transaccion, bueno son barios botones y en todas me sale el mismo error :

    Y bueno para la conexion yo hice una clase aparte para que no tenga que poner la conexion en todas las clases, si no solo llamarla
    quizas eso sea el problema, les paso el codigo de mi clase conexion:

    Imports System.Data
    Imports System.Data.SqlClient
    Public Class Class_conexion
        Dim con As New SqlConnection
        Public Function conectar() As SqlConnection
            Try
                con = New SqlConnection
                con.ConnectionString = "Data Source=.;Initial Catalog=examen_final;Integrated Security=True"
                con.Open()
            Catch ex As Exception
                MsgBox(ex.Message, MsgBoxStyle.Critical, "Error")
            End Try
            Return con
        End Function
        Public Sub desconectar()
            If con.State = ConnectionState.Open Then
                con.Close()
                con = Nothing
            End If
        End Sub
    End Class
    Y Bueno el boton en donde hago la trasaccion es esta:
        Private Sub btn_modif_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_modif.Click
            'Instanciar nuevo SqlTransaction  
            Dim tran As SqlTransaction = Nothing
            Try
                con.conectar()
                '  Establecer e iniciar la nueva transacción con BeginTransaction
                tran = con.conectar.BeginTransaction
    
                Dim cmd As New SqlCommand("actualizar_cliente'" & txt_id.Text & "','" & txt_nomb.Text & "','" & txt_ap.Text & "','" & mskfecha.Text & "','" & txt_dni.Text & "','" & msktxt_cel.Text & "','" & txt_email.Text & "'", con.conectar)
    
                cmd.Transaction = tran
                cmd.ExecuteNonQuery()
                limpiar()
                MsgBox("Codigo modificado correctamente")
                tran.Commit()
            Catch ex As Exception
                ' cancelar la transacción en caso de error en el   
                'segundo comando con el método Rollback
                If Not tran Is Nothing Then
                    tran.Rollback() 'deshacer  
                End If
                MsgBox(ex.Message, MsgBoxStyle.Information, "no pudo modificar")
            Finally
                ' cerrar la conexión
                If Not con Is Nothing Then
                    If con.conectar.State = ConnectionState.Open Then
                        con.desconectar()
                    End If
                End If
            End Try
            Call limpiar()
        End Sub

    Espero que me respondan lo mas pronto posible, es que me urge..
    Bueno gracias de antemano, y espero que me ayuden, eso de las transacciones es nuevo para mi y la verdad no se que pueda hacer :S

    domingo, 8 de abril de 2012 6:23

Respuestas

  • [...] no me queda muy claro, no se como llamar a la misma conexion, no lo entiendo :S ,Le agradeceria si pone un ejemplo para de ahi poder guiarme please..

    Aquí van los cambios:

    Imports System.Data
    Imports System.Data.SqlClient
    Public Class Class_conexion
        Private con As SqlConnection = Nothing
        Public Function conectar() As SqlConnection
            If Not con Is Nothing Return con
            Try
                con = New SqlConnection
                con.ConnectionString = "Data Source=.;Initial Catalog=examen_final;Integrated Security=True"
                con.Open()
            Catch ex As Exception
                MsgBox(ex.Message, MsgBoxStyle.Critical, "Error")
            End Try
            Return con
        End Function
        Public Sub desconectar()
            If con.State = ConnectionState.Open Then
                con.Close()
                con = Nothing
            End If
        End Sub
    End Class

    Observa que primero se comprueba si la conexión ya está inicializada, y en ese caso se devuelve. En caso contrario, se procede como en el caso anterior, inicializando y abriendo la conexión. De paso, he quitado el "New" de la declaración de la variable con, que era superfluo (ya que creaba un objeto innecesario, puesto que más abajo ya se hace el New en el cuerpo de la rutina -- nótese que este comportamiento ha cambiado respecto a VB6, lo digo por si venías de dicho entorno antiguo).

    Como nota adicional, aunque esto funcionará no resulta elegante del todo porque no garantiza el cierre de la conexión en todos los casos. Idealmente, esta clase class_conexion debería implementar IDisposable, y sería conveniente llamarla mediante una construcción "Using...End Using". Pero si todavía no manejas suficientemente bien este entorno de desarrollo, es mejor que estos refinamientos los dejes para cuando lo tengas más dominado.

    Y otra nota más: Aunque usar un TransactionScope resolvería el error que se te produce con las transacciones, no resolvería el problema de que abres conexiones superfluas que te dejas sin cerrar, por lo que en todo caso deberías corregir el class_conexion, incluso aunque finalmente te decidas a usar el TransactionScope.

    • Marcado como respuesta mellega lunes, 9 de abril de 2012 22:18
    lunes, 9 de abril de 2012 6:08

Todas las respuestas

  • El mensaje de error tiene toda la razón: la transacción no pertenece a la misma conexión. Fíjate que tu rutina "conectar" devuelve una conexión NUEVA cada vez que la llamas. Tu proograma la llama cuatro veces: una al principio del Try, cuando llamas a con.conectar. Esto crea una nueva conexión, la abre, y a continuación la "tira" (porque no la guardas en ningún sitio). Después creas otra conexión en con.connect.Begintransaction. Después llamas otra vez a con.conectar en el constructor del cmd. Esto te devuelve otra nueva conexión abierta, que se guarda dentro del cmd y es la que realmente se usa cuando llamas al ExecuteNonQuery (y siempre se queda sin cerrrar). Finalmente llamas a con.conectar.State, que crea una nueva conexión, que es la que finalmente cierras debajo (pero las tres primeras se te quedan abiertas, y de esas tres, la que tiene la transacción es distinta de la que tiene el command, por eso te da un error).

    Solución: Arregla la función "conectar" para que use el patrón "singleton", es decir que sólo cree una conexión si no está ya creada, pero si ya está creada, que te devuelva la conexión existente en lugar de hacer un "New" para crear otra nueva.

    domingo, 8 de abril de 2012 21:20
  • Solución: Arregla la función "conectar" para que use el patrón "singleton", es decir que sólo cree una conexión si no está ya creada, pero si ya está creada, que te devuelva la conexión existente en lugar de hacer un "New" para crear otra nueva.

    Bueno como le digo no manejo muy bien esto, y pues quiesiera aprender, Gracias por responderme, pero no me queda muy claro, no se como llamar a la misma conexion, no lo entiendo :S ,Le agradeceria si pone un ejemplo para de ahi poder guiarme please..
    domingo, 8 de abril de 2012 22:18
  • hola

    estas usando sql server porque no usas el TransactionScope

    para administrar la transaccion, es mucho mas simple de usar el el BeginTransaction


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina

    domingo, 8 de abril de 2012 22:38
  • hola

    estas usando sql server porque no usas el TransactionScope

    para administrar la transaccion, es mucho mas simple de usar el el BeginTransaction


    Hola
    Cual es la diferencia entre esos dos, es un trabajo que dejo el profesor, en el cual dijo que usaramos transacciones, y especifico (BeginTransaction, commit)
    por eso estoy usando, pero si hacen la misma cosa, entonces lo podria usar, pero en que se diferencian ? :S
    domingo, 8 de abril de 2012 23:10
  • TransactionScope es mucho mas simple de implementar y no requieres una conexion unica y el ir pasando el objeto transaction de operacion en operacion

    a nivel de codigo queda mil veces mas limpio

    lo unico es que necesitas del servicio de Microsoft Distributed Transaction Coordinator (MSDTC), pero este por lo general esta habilitado


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina

    lunes, 9 de abril de 2012 0:37
  • TransactionScope es mucho mas simple de implementar y no requieres una conexion unica y el ir pasando el objeto transaction de operacion en operacion

    a nivel de codigo queda mil veces mas limpio

    lo unico es que necesitas del servicio de Microsoft Distributed Transaction Coordinator (MSDTC), pero este por lo general esta habilitado


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina

    Entonces los dos hacen la misma cosa, pero de diferente forma..?
    aclarame eso please, porqe mi profesor estaba explicando que el BeginTransaction sirve por ejemplo para cuando se va el servicio electrico, en pleno trabajo de la maquina, entonces todo lo que estaba siendo grabado en ese instante se borra , al aplicar el rollback, y se queda como antes, ya que al irse el servicio electrico el programa puede grabar cualquier cosa, y ese es el objetivo del trabajo, por eso le digo, el TransactionScope hace lo mismo pero de otra manera, o me equivoco..? :S
    lunes, 9 de abril de 2012 2:41
  • [...] no me queda muy claro, no se como llamar a la misma conexion, no lo entiendo :S ,Le agradeceria si pone un ejemplo para de ahi poder guiarme please..

    Aquí van los cambios:

    Imports System.Data
    Imports System.Data.SqlClient
    Public Class Class_conexion
        Private con As SqlConnection = Nothing
        Public Function conectar() As SqlConnection
            If Not con Is Nothing Return con
            Try
                con = New SqlConnection
                con.ConnectionString = "Data Source=.;Initial Catalog=examen_final;Integrated Security=True"
                con.Open()
            Catch ex As Exception
                MsgBox(ex.Message, MsgBoxStyle.Critical, "Error")
            End Try
            Return con
        End Function
        Public Sub desconectar()
            If con.State = ConnectionState.Open Then
                con.Close()
                con = Nothing
            End If
        End Sub
    End Class

    Observa que primero se comprueba si la conexión ya está inicializada, y en ese caso se devuelve. En caso contrario, se procede como en el caso anterior, inicializando y abriendo la conexión. De paso, he quitado el "New" de la declaración de la variable con, que era superfluo (ya que creaba un objeto innecesario, puesto que más abajo ya se hace el New en el cuerpo de la rutina -- nótese que este comportamiento ha cambiado respecto a VB6, lo digo por si venías de dicho entorno antiguo).

    Como nota adicional, aunque esto funcionará no resulta elegante del todo porque no garantiza el cierre de la conexión en todos los casos. Idealmente, esta clase class_conexion debería implementar IDisposable, y sería conveniente llamarla mediante una construcción "Using...End Using". Pero si todavía no manejas suficientemente bien este entorno de desarrollo, es mejor que estos refinamientos los dejes para cuando lo tengas más dominado.

    Y otra nota más: Aunque usar un TransactionScope resolvería el error que se te produce con las transacciones, no resolvería el problema de que abres conexiones superfluas que te dejas sin cerrar, por lo que en todo caso deberías corregir el class_conexion, incluso aunque finalmente te decidas a usar el TransactionScope.

    • Marcado como respuesta mellega lunes, 9 de abril de 2012 22:18
    lunes, 9 de abril de 2012 6:08
  • el TransactionScope hace lo mismo pero de otra manera, o me equivoco..?

    el TransactionScope hace lo mismo pero de una forma mas elegante en el codigo


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina

    lunes, 9 de abril de 2012 12:17
  • Gracias Alberto eres mi idolo..¡ xD
    Falto cerrar el condicional If, pero bueno
    eso es facil de resolver.. deveras Gracias por aclararmelo
    Ya me funciona el programa con transacciones
    Muy agradecido.xD
    lunes, 9 de abril de 2012 22:23