none
controlar error al almacenar datos de un datagridview en SQL

    Pregunta

  • Buenas Tardes

    Espero me entiendan. Siempre he tenido este inconveniente y quisiera que me ayudaran a solucionarlo.

     

    SITUACION: 

    Quiero insertar unas filas de un datagridview en una tabla SQL. para ello debo utilizar un Procedimiento Almacenado que controle errores con ROLLBACK TRAN.

    PROBLEMA:

    suponiendo que de las 10 Filas que quiero insertar en SQL, la numero 6 tiene un error ya sea de tamaño o de tipo de Dato. Con el código que tengo actualmente y que relaciono mas abajo, el sistema me guarda las 5 primeras filas. y lo que quiero es que me devuelva el proceso ya que al encontrar el error en la  fila 6 no pudo continuar insertando las 10 filas y la información me queda incompleta.

    Según mi código el va ejecutando el procedimiento fila por fila y solo valida el momento en que va a insertar sin importar el resto de filas.

     

    Espero me ayuden ya que lo que quiero es enviar el grupo completo de filas y no una a una.

    o si es una a una que el procedimiento me haga el ROLLBACK de todas las filas que ya habían sido guardadas antes de presentarse el error.

     

    SQL PROCEDIMIENTO ALMACENADO

    CREATE PROCEDURE  PA_Guardar_Permiso
    (
    @Id_Permiso Varchar(5),
    @Id_Modulo Varchar(5),
    @Perfil SmallInt,
    @Estado Varchar(1)
    )
    AS
    BEGIN TRY
    BEGIN TRANSACTION -- Inicio de la Transaccion..
    ------------------------------------------
    IF EXISTS (SELECT R.Id_Permiso FROM CON_R_PERM_MODU_PERF R inner join CON_PERFIL P on R.Id_Perfil=P.Id_Perfil WHERE Id_Permiso=@Id_Permiso And P.Descripcion=@Perfil)
    UPDATE CON_R_PERM_MODU_PERF SET Estado=@Estado WHERE Id_Permiso= @Id_Permiso
    And EXISTS (SELECT *FROM CON_PERFIL WHERE CON_PERFIL.Id_Perfil=CON_R_PERM_MODU_PERF.Id_Perfil And CON_PERFIL.Descripcion=@Perfil)
    ELSE INSERT INTO CON_R_PERM_MODU_PERF (Id_Permiso,Id_Modulo,Id_Perfil,Estado)
    SELECT @Id_Permiso,@Id_Modulo,P.Id_Perfil,@Estado FROM CON_PERFIL P where P.Descripcion=@Perfil
    --------------------------------------------------------
    COMMIT TRAN -- Transacion Exitosa!
    END TRY
    BEGIN CATCH
    IF @@TRANCOUNT > 0
    ROLLBACK TRAN --RollBack en Caso de Error
    END CATCH
    GO

     

    VB .NET

    SqlCommand = New SqlCommand("PA_Guardar_Permiso", clsConexion.Abrir)
    For Each Row As DataGridViewRow In DataGridView1.Rows
    Dim Estado_Permiso As Integer = Row.Cells(3).Value
    SqlCommand.Parameters.Clear()
    SqlCommand.Parameters.AddWithValue("@Id_Permiso", Row.Cells(0).Value)
    SqlCommand.Parameters.Add("@Perfil", SqlDbType.VarChar, 50).Value = ComboBox1.Text
    SqlCommand.Parameters.Add("@Id_Modulo", SqlDbType.VarChar, 5).Value = "INV"
    SqlCommand.Parameters.Add("@Estado", SqlDbType.VarChar, 1).Value = Estado_Permiso
    SqlCommand.CommandType = CommandType.StoredProcedure
    SqlCommand.ExecuteNonQuery()
    Next
    clsConexion.Cerrar()

     

    Gracias por su amable colaboracion

     

     

     

    viernes, 31 de mayo de 2013 0:41

Respuestas

  • hola

    pero las transacciones no als debes definir en el procedure, las tiens que definir en el codigo

    como tu lo haces cada linea que envias es una nueva transaccion, de la forma que lo haces deberias enviar todos los registros de una una llamda al procedure y realizar el loop dentro del mismo procedure

    ese for each que ahces en vb.net no aplica como lo estas encarando

    tienes que usar el SqlTransaction

    Using the SqlTransaction Object

    las transaciones dentro del procedure puees quitarlas

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina

    • Marcado como respuesta alexcandela sábado, 1 de junio de 2013 1:20
    viernes, 31 de mayo de 2013 1:40

Todas las respuestas

  • hola

    pero las transacciones no als debes definir en el procedure, las tiens que definir en el codigo

    como tu lo haces cada linea que envias es una nueva transaccion, de la forma que lo haces deberias enviar todos los registros de una una llamda al procedure y realizar el loop dentro del mismo procedure

    ese for each que ahces en vb.net no aplica como lo estas encarando

    tienes que usar el SqlTransaction

    Using the SqlTransaction Object

    las transaciones dentro del procedure puees quitarlas

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina

    • Marcado como respuesta alexcandela sábado, 1 de junio de 2013 1:20
    viernes, 31 de mayo de 2013 1:40
  • Por qué no usas LinQ To SQL (o LinQ To Classes? no recuerdo bien como se llama), así cada proceso lo hace usando Transactions además que todos los Valores que introduzcas en las "querys" pasan como Parámetros, es muy fácil y sin tanto rollo de usar objetos como SqlConnection, SqlCommand, SqlDataAdapter, DataTable, DataReader etc... Además de que puedes "vincular" controles del Formulario a objetos BindingSource y esto hace mucho más fácil los métodos Insertar, Actualizar, Eliminar, etc...

    Tan Fácil como hacer DataContext.SubmitChanges()

    A menos que necesitas un gran "Rendimiento y Velocidad" en los procesos, pero LinQ es bastante rápido.

    Además que si Vinculas por ejm un List(Of Objeto) al DataGridView, solo tendrias que hacer algo como:

    DataContext.NombreTabla.InsertAllOnSubmit(ListaGenerica)

    DataContext.SubmitChanges()

    Y guardas Todas las líneas del DataGridView en la Base de Datos.

    viernes, 31 de mayo de 2013 2:17
  • Gracias Leandro, seguí lo que me indicaste y me funciono perfectamente. Cambie le modo de leer el datagridview. (Pero me queda la inquietud si la forma correcta de leerlo es con Each)

    Adicional estuve leyendo algo sobre sp_cursor  no se si eso aplica para mi caso. ya que lo que en realidad quería es usar un procedimiento almacenado. pero por lo pronto muchas gracias ya que solucionaste mi problema de una manera sencilla.

    Dejo el código:

    Try

    Dim Conexion = clsConexion.Abrir
    Transaction = Conexion.BeginTransaction
    '---------------GUARDAR-------------------
    For k As Integer = 0 To DataGridView1.Rows.Count - 1
    SqlCommand = New SqlCommand("IF EXISTS (SELECT R.Id_Permiso   FROM  CON_R_PERM_MODU_PERF R inner join CON_PERFIL P on R.Id_Perfil=P.Id_Perfil " & _
    "WHERE Id_Permiso='" & DataGridView1.Rows(k).Cells(0).Value & "' And P.Descripcion='" & ComboBox1.Text & "')" & _
    "UPDATE CON_R_PERM_MODU_PERF SET Estado='" & DataGridView1.Rows(k).Cells(3).Value & "' WHERE Id_Permiso='" & DataGridView1.Rows(k).Cells(0).Value & "'" & _
    "And EXISTS (SELECT *FROM CON_PERFIL WHERE CON_PERFIL.Id_Perfil=CON_R_PERM_MODU_PERF.Id_Perfil And CON_PERFIL.Descripcion='" & ComboBox1.Text & "')" & _
    "ELSE INSERT INTO CON_R_PERM_MODU_PERF (Id_Permiso,Id_Modulo,Id_Perfil,Estado) " & _
    "SELECT '" & DataGridView1.Rows(k).Cells(0).Value & "','INV',P.Id_Perfil,'" & DataGridView1.Rows(k).Cells(3).Value & "' FROM CON_PERFIL P where P.Descripcion='" & ComboBox1.Text & "'", Conexion)
    SqlCommand.Transaction = Transaction
    SqlCommand.ExecuteNonQuery()
    Next
    Transaction.Commit()
    clsConexion.Cerrar()
    '---LIMPIAR CAMPOS--------
    Limpiar()
    Cargar_Datos()
    MsgBox("Datos Guardados")
    '-----------------------
    Catch Exp As SqlClient.SqlException
    Transaction.Rollback()
    clsConexion.Cerrar()
    MessageBox.Show(Exp.Message, "lP_Aceptar", MessageBoxButtons.OK, MessageBoxIcon.Information)
    Catch Exp As Exception
    Transaction.Rollback()
    clsConexion.Cerrar()
    MessageBox.Show(Exp.Message, "lP_Aceptar", MessageBoxButtons.OK, MessageBoxIcon.Information)
    End Try

    sábado, 1 de junio de 2013 1:29
  • OK muchas gracias por tu sugerencia. voy a empezar a leer mas sobre LINQ ya que siempre he tenido  la intención de aplicarlo en mis proyectos. y pues con esto me da mas animo para explorar nuevas técnicas. 
    sábado, 1 de junio de 2013 1:31