none
Fragmento de Código de Control de concurrencia RRS feed

  • Pregunta

  • Hola Todos,

    El Estado Buscando Un Fragmento de Código en vb.net o C # Que en la capa de Acceso a Datos me muestre Como implementar el control de concurrencia de, embargo pecado, me ha Sido díficil. Ya comprendo los concepts, no obstante, Estoy confundido párrafo implementarlo. Trabajo con MYSQL. Él encontrado el Siguiente FRAGMENTO Que MÁS sí aproxima, embargo pecado, me parece MÁS Fácil hacerlo (quizas Por Que él más leído Sobre el Tema) con la ONU campo TimeStamp, Pero no implementarlo. Aqui esta el codigo Que Encontre.

    Si Alguien Florerias modificarlo párr utilizar TimeStamp, please sí lo agradezco, Sobre Todo en el campo TimeStamp Obtener Que lo llamo f_modifica:

     Dim nwindConn As SqlConnection = New SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind")
    
      Dim custDA As SqlDataAdapter = New SqlDataAdapter("SELECT CustomerID, CompanyName FROM Customers ORDER BY CustomerID", nwindConn)
    
      ' The Update command checks for optimistic concurrency violations in the WHERE clause.
      custDA.UpdateCommand = New SqlCommand("UPDATE Customers (CustomerID, CompanyName) VALUES(@CustomerID, @CompanyName) " & _
                                            "WHERE CustomerID = @oldCustomerID AND CompanyName = @oldCompanyName", nwindConn)
      custDA.UpdateCommand.Parameters.Add("@CustomerID", SqlDbType.NChar, 5, "CustomerID")
      custDA.UpdateCommand.Parameters.Add("@CompanyName", SqlDbType.NVarChar, 30, "CompanyName")
    
      ' Pass the original values to the WHERE clause parameters.
      Dim myParm As SqlParameter
      myParm = custDA.UpdateCommand.Parameters.Add("@oldCustomerID", SqlDbType.NChar, 5, "CustomerID")
      myParm.SourceVersion = DataRowVersion.Original
      myParm = custDA.UpdateCommand.Parameters.Add("@oldCompanyName", SqlDbType.NVarChar, 30, "CompanyName")
      myParm.SourceVersion = DataRowVersion.Original
    
      ' Add the RowUpdated event handler.
      AddHandler custDA.RowUpdated, New SqlRowUpdatedEventHandler(AddressOf OnRowUpdated)
    
      Dim custDS As DataSet = New DataSet()
      custDA.Fill(custDS, "Customers")
    
      ' Modify the DataSet contents.
    
      custDA.Update(custDS, "Customers")
    
      Dim myRow As DataRow
    
      For Each myRow In custDS.Tables("Customers").Rows
        If myRow.HasErrors Then Console.WriteLine(myRow(0) & vbCrLf & myRow.RowError)
      Next
    
    
    Private Shared Sub OnRowUpdated(sender As object, args As SqlRowUpdatedEventArgs)
      If args.RecordsAffected = 0
        args.Row.RowError = "Optimistic Concurrency Violation Encountered"
        args.Status = UpdateStatus.SkipCurrentRow
      End If
    End Sub
    

    Aprecio Su valiosa Colaboración-


    Saludos, Solph.



    • Editado Solp domingo, 18 de noviembre de 2012 11:25
    domingo, 18 de noviembre de 2012 11:18

Todas las respuestas

  • ¿Usó algún traductor automático?  La pregunta es caótica.

    En fin, creo que usted quiere saber cómo usar Timestamp.  Es sencillo:

    Update Tabla
    Set campos = valores
    Where ID = @id AND campoDeTimestamp = @timestamp;

    Básicamente así se hace el UPDATE.  Afectará cero registros si el timestamp cambió.  ¿Le aclara la situación?


    Jose R. MCP
    Code Samples

    domingo, 18 de noviembre de 2012 19:18
  • Gracias WebJose,

    Disculpe la traducción....

    La parte que deseo conocer es como obtengo el parámetro @timestamp.

    Como tráigo ese valor? he de usar un datatable? ¿con qué instruccion conozco la cantidad de regs. afectados?,

    cómo controlar para indicarle al usuario que hubo una violacion a la concurrencia?

    Agradezco su ayuda


    Saludos, Solph.

    domingo, 18 de noviembre de 2012 21:16
  • Ese valor puede obtenerse como un arreglo de 8 bytes usando ADO.net.  Se obtiene igual que cualquier otro valor:

    //Asumiendo un SqlDataReader:
    byte[] timestamp = (byte[])reader["ElNombreDeCampoDelTimestamp"];
    
    //Y se envía a una consulta parametrizada de igual manera:
    using (SqlCommand cmd = new SqlCommand(...))
    {
        cmd.Parameters.AddWithValue("TimestampAnterior", elArrayDeBytes);
        ...
    }

    Como verá, no hace falta tener un DataTable.  El valor se obtiene y se transmite fácilmente.

    La función T-SQL @@RowCount le dirá cuántos registros fueron afectados.  Si fue cero entonces no hubo coincidencias de registros.  Tiene entonces dos opciones:  Asumir que el ID es correcto y por lo tanto decidir que no hubo UPDATE porque el timestamp cambió (el registro cambió después de ser leído por el usuario X, probablemente por otro usuario Y), o bien puede usted tomarse la molestia de hacer un IF(Exists( Select * From tabla where ID = @ID)) para tener la seguridad que el ID es bueno y que efectivamente hubo cero registros afectados por culpa de un timestamp que cambió.


    Jose R. MCP
    Code Samples


    • Editado webJose domingo, 18 de noviembre de 2012 22:25
    • Marcado como respuesta Solp domingo, 18 de noviembre de 2012 23:34
    • Desmarcado como respuesta Solp domingo, 18 de noviembre de 2012 23:39
    domingo, 18 de noviembre de 2012 22:22
  • Hola Webjose

    Gracias por tu disposición a ayudar....

    he intentado realizar los pasos que me dices... solo que trabajo con MYSQL y vb.net. Aquí está el código:

    Public Shared Function Update(ByVal bancos As BancosEN) As Boolean
    
    
            Dim conn As New MySqlConnection
            '--
            Dim objconn As New Conexion
    
            Try
                conn = objconn.open
    
                'Asumiendo un SqlDataReader:
                Dim reader As MySqlDataReader = Nothing
                Dim timestamp As Byte() = DirectCast(reader("f_modifica"), Byte())
    
                Dim sql As String = "UPDATE Bancos (Nombre) VALUES(?Nombre) " & _
                        "WHERE id_banco = ?id_banco and f_modifica = ?timestamp"
    
    
                'Y se envía a una consulta parametrizada de igual manera:
                Using cmd As New MySqlCommand(sql, conn)
    
                    cmd.Parameters.AddWithValue("f_modifica", timestamp)
                    cmd.Parameters.AddWithValue("?nombre", bancos.nombre)
                    cmd.Parameters.AddWithValue("?id_banco", bancos.id_banco)
    
                End Using
    
                'ejecuta y cierra la conexion
    
                cmd.ExecuteNonQuery()
    
                conn.Close()
    
                '--------------------------------------
                'aqui iría la validacion de cuantos registros afectados 
                'no sé cual sería en MYSQL la funcion para conocer los regs. afectados
                '
                '--------------------------------------
    
    
                Return True
    
            Catch ex As Exception
                MsgBox("Error al guardar" & vbCrLf & _
                       "Consulte a su administrador de sistema", MsgBoxStyle.Critical, "Info")
                Return False
            End Try
    
        End Function

    Tengo duda en esta expresion de los parametros:

    cmd.Parameters.AddWithValue("f_modifica", timestamp)

    teniendo en cuenta que la instruccion sql es:

                Dim sql As String = "UPDATE Bancos (Nombre) VALUES(?Nombre) " & _
                        "WHERE id_banco = ?id_banco and f_modifica = ?timestamp"
    

    es así o "?f_modifica" o "?timestamp", timestamp)

    Por favor, quisiera su opinion acerca de si estoy bien...

    Gracias


    Saludos, Solph.

    domingo, 18 de noviembre de 2012 23:16
  • Sería "?timestamp", diría yo.  Nunca he usado MySQL así que no le sé decir a ciencia cierta.

    Tampoco puedo asegurar que el timestamp de MySQL se adhiera a mi explicación, que fue basada en SQL Server.  Espero que le funcione igual.


    Jose R. MCP
    Code Samples

    domingo, 18 de noviembre de 2012 23:18
  • Muchas gracias ha sido de gran ayuda...

    Yo aprecio su paciencia, y disposición

    voy a probar ... Gracias 


    Saludos, Solph.

    domingo, 18 de noviembre de 2012 23:33
  • Hola,

    A mi me parece que si vos pretendes administrar los bloqueos marcando los registos en un campo timestamp vas por muy mal camino.

    El bloqueo de los registros dejalo que lo administre el motor que seguramente lo hara mejor que vos, a vos solo lo que te debe interesar es el manejo de los erroes que te puede llegar a devolver el motor y en funcion de eso proceder segun tus opciones o logica del proceso.

    En la mayoria de las bases de datos, por no decir todas, cuando se produce un bloqueo el motor queda esperando hasta que la transaccion que lo bloqueo lo desbloquee.

    Por otro lado supongamos que a la base de datos le agregas trigers, como vas a hacer para controlar el timestamp de las tablas que modifican ese triger si no estan a tu alcance ?.

    Victor Koch.

    martes, 20 de noviembre de 2012 13:51
  • Victor, el timestamp no viene a resolver problemas de concurrencia de ese tipo.  Específicamente, el timestamp está diseñado para resolver un problema en particular:  Usuario A lee registro X; usuario B lee registro X; usuario B modifica registro X y lo guarda; usuario A modifica registro X y lo guarda.  Resultado final:  Lo que guardó usuario B se pierde porque usuario A nunca se dio cuenta que usuario B modificó el registro en ese lapso de tiempo.  El uso del timestamp resuelve esto asegurándose que el timestamp no ha cambiado desde la última vez que se leyó el registro.


    Jose R. MCP
    Code Samples

    martes, 20 de noviembre de 2012 14:12
  • Hola Webjose,

    Tal vez para casos muy especificos funcione o mejor dicho es una forma para solucionarlo.

    Ahora bien.... asegurate de escribir bien el codigo y no dejes ninguna puerta abierta. 

    Si analizamos un poco los casos suena raro que dos terminales intenten, por ejemplo, modificar la razon social de un cliente en particular y una pretende cambiarla por Juan y la otra por Pedro.

    Por mi parte en mis aplicaciones cuando actualizo un registro, por ejemplo un maestro de clientes, articulos, etc,.etc. solo actualizo el campo que se modifico desde la lectura al momento que el operador decide ingresar a modificar hasta la confirmacion del operador, o sea no actualizo todos los campos del registro solo los campos modificados.   

    Victor Koch.

    martes, 20 de noviembre de 2012 14:36
  • Hola Victor,

    Gracias por tus comentarios.

    Me parece muy interesante lo mencionaste de como actualizas tus tablas... me gustaría, si es posible, que me detallaras más es que soy nuevo en el tema de concurrencias, pues siempre había programado para una sola máquina.

    Podrías ponerme un ejemplo? o si tienes un proyecto de ejemplo sencillo podrías pasarmelo?

    mi email es: solphy@hotmail.com

    Te agradezco tu valiosa ayuda.


    Saludos, Solph.

    martes, 20 de noviembre de 2012 16:19
  • Hola,

    Te voy a enviar un documento que escribi el cual habla de bloqueos y transacciones. Si bien es muy basico te va a ayudar para entender los principios basicos.

    Victor Koch.

    martes, 20 de noviembre de 2012 16:28
  • gracias Victor....

    Si tienes ejemplos mejor...


    Saludos, Solph.

    martes, 20 de noviembre de 2012 16:37