ROLLBACK EM VRIAS TABELAS

 Tópico anterior Próximo tópico Novo tópico

ROLLBACK EM VRIAS TABELAS

VB.NET

 Compartilhe  Compartilhe  Compartilhe
#486807 - 30/01/2019 13:26:45

DAMASCENO.CESAR
ADAMANTINA
Cadast. em:Fevereiro/2009


Boa tarde, tenho um projeto aqui onde ao inserir dados preciso inserir partes dos dados em 4 tabelas diferentes, sei que com o rollback, consigo retornar o ultimo registro, mas gostaria de uma orientao da melhor forma de realizar esse rollback (nas tabelas alteradas) caso ocorra algum erro
Uso banco de dados MySQL
Vou dar um exemplo de como faco isso:
  Public Function IncluirNrComuInterno(ByVal CMN As ClsNrComunicado) As Integer
        Dim sql As String = [][]
        Try

            Dim parametrosNomes(2) As String
            parametrosNomes(0) = []@numInterno[]
            parametrosNomes(1) = []@Ano[]
            parametrosNomes(2) = []@Data[]

            Dim parametrosValores(2) As String
            parametrosValores(0) = CMN.NumInterno
            parametrosValores(1) = CMN.Ano
            parametrosValores(2) = Format(CMN.Data, []yyyy-MM-dd[])
            sql = []INSERT INTO NrComunicado (NumInterno, Ano, Data) VALUES (@NumInterno, @Ano, @Data);[]
            Dim Dado As New Dados.Manipula
            Return Dado.Crud(sql, parametrosNomes, parametrosValores)
        Catch ex As Exception
            Throw ex
        End Try
    End Function


agora o CRUD

   Private Sub FillParameters(ByVal command As MySqlCommand, ByVal parameterNames As String(), ByVal parameterVals As String())
        Try
            If parameterNames IsNot Nothing Then
                For i = 0 To parameterNames.Length - 1
                    command.Parameters.AddWithValue(parameterNames(i), parameterVals(i))
                Next
            End If
        Catch ex As Exception
            Throw
        End Try
    End Sub

    Public Function Crud(ByVal sSQL As String, ByVal Parametro As String(), ByVal Valores As String()) As Integer
        Try
            Using connection As MySqlConnection = AbreConexao()
                Using command As New MySqlCommand(sSQL, connection)
                    FillParameters(command, Parametro, Valores)
                    Return command.ExecuteNonQuery()
                End Using
            End Using
        Catch ex As Exception
            Throw
        End Try
    End Function

Baseado nesse cdigo, para 4 tabelas distintas, como utilizar o rollback
PS: no quero codgo pronto, apenas como puxar o rollback em cada insert que der erro e cancelar os lancamentos j feitos


O conhecimento como o dinheiro: quanto mais temos, mais queremos ter (Josh Billings)  


Resposta escolhida #486810 - 30/01/2019 16:21:17

KERPLUNK
RIO GRANDE DO SUL
Cadast. em:Junho/2009


Membro da equipe
Do jeito que est, no tem como, voc vai ter que repassar uma transaction entre cada um dos comandos. Ou passar todos os comandos desejados para uma rotina que os executa dentro de uma transation, mais ou menos assim:

Public Sub RunTransaction(myConnString As String)
Dim myConnection As New MySqlConnection(myConnString)
myConnection.Open()

Dim myCommand As MySqlCommand = myConnection.CreateCommand()
Dim myTrans As MySqlTransaction

[] Start a local transaction
myTrans = myConnection.BeginTransaction()
[] Must assign both transaction object and connection
[] to Command object for a pending local transaction
myCommand.Connection = myConnection
myCommand.Transaction = myTrans

Try
myCommand.CommandText = []Insert into Region (RegionID, RegionDescription) VALUES (100, []Description[])[]
myCommand.ExecuteNonQuery()
myCommand.CommandText = []Insert into Region (RegionID, RegionDescription) VALUES (101, []Description[])[]
myCommand.ExecuteNonQuery()
myTrans.Commit()
Console.WriteLine([]Both records are written to database.[])
Catch e As Exception
Try
myTrans.Rollback()
Catch ex As MySqlException
If Not myTrans.Connection Is Nothing Then
Console.WriteLine([]An exception of type [] & ex.GetType().ToString() & _
[] was encountered while attempting to roll back the transaction.[])
End If
End Try

Console.WriteLine([]An exception of type [] & e.GetType().ToString() & _
[]was encountered while inserting the data.[])
Console.WriteLine([]Neither record was written to database.[])
Finally
myConnection.Close()
End Try
End Sub []RunTransaction


_______________________________________________________________________
Virei Orculo!
The end is nigh, be ready for the nukes!


#486811 - 30/01/2019 20:15:58

FOXMAN
BARRETOS
Cadast. em:Janeiro/2001


Membro da equipe
Se vc utiliza INNODB, e as tabelas esto relacionadas(chave estrangeira), acredito que a forma talvez mais tranquila seria fazer esse rollback na unha mesmo, excluindo os dados da tabela principal e consequentemente todos os registros das tabelas relacionadas sero excluidos....
Podes at fazer uma funo para esse roolback, passando como parametro o id principal dos registros, e validando as demais tabelas....

apenas uma sugesto......



Grupo DotNet.Br no FaceBook

Grupo WhatsDev



#486822 - 31/01/2019 11:20:52

DAMASCENO.CESAR
ADAMANTINA
Cadast. em:Fevereiro/2009


Desculpem a demora em responder, estava testando as ideias sugeridas
FOXMAN, meu conhecimento em Banco de Dados pequeno, tentei criar chaves estrangeiras com os campos j existentes, que, de certa forma se repetem, mas deu erro rsrsrs
ento abandonei a ideia por enquanto, preciso e vou aprender mais sobre isso.

KERP, me baseei em sua ideia e, me parece que deu certo, preciso realizar mais testes e ver se ainda h algum erro meu, mas o resultado ficou assim

  Public Function InsereVarios(ByVal AUP As ClsAutoProced, ByVal Autor As ClsAutorComunicado, ByVal BdCom As ClsBdComunicado, Comu As ClsComunicados, ByVal NR As ClsNrComunicado) As Integer

        Dim CONEXAO As New MySqlConnection(MinhaConexao)
        CONEXAO.Open()
        Dim CMD As MySqlCommand = CONEXAO.CreateCommand
        Dim MyTrans As MySqlTransaction
        Dim RSP As Integer = 0
        MyTrans = CONEXAO.BeginTransaction()

        CMD.Connection = CONEXAO
        CMD.Transaction = MyTrans

        Try
            Dim sSQL As String
            sSQL = []INSERT INTO AutoProced (NumInterno, Ano, Matricula, Nome, Referencia, DataFalta) [] _
                & []VALUES (@NumInterno, @Ano, @Matricula, @Nome, @Referencia, @DataFalta)[]
            CMD.CommandText = sSQL
            CMD.CommandType = CommandType.Text
            Dim dAUP As New AutoProced
            dAUP.PassaParametroAutoProced(AUP, CMD)
            If CMD.ExecuteNonQuery() = 0 Then Return 0
            CMD.Parameters.Clear()

            Dim nAutor As New AutorComunicado
            CMD.CommandText = []INSERT INTO AutorComunicado (Ano, Matricula, NumInterno) VALUES (@Ano, @Matricula, @NumInterno);[]
            nAutor.PassaParametroAutorComunicado(Autor, CMD)
            CMD.ExecuteNonQuery()
            CMD.Parameters.Clear()

            sSQL = []INSERT INTO BdComunicado (Ano, Dependencia, Natureza, Local, DtFato, HoraFato, DtComunica, HoraComunica, [] _
                & [] Autor, RaioCela, Vitima, Testemunha, Apreensao, Historico, Comunicante, RgComunica, NumInterno) VALUES [] _
                & [](@Ano, @Dependencia, @Natureza, @Local, @DtFato, @HoraFato, @DtComunica,@HoraComunica, [] _
                & []@Autor, @Raiocela, @Vitima, @Testemunha, @Apreensao, @Historico, @Comunicante, @RgComunica, @NumInterno);[]
            CMD.CommandText = sSQL
            Dim nBdCom As New BdComunicados
            nBdCom.PassaParametroBdComunicado(BdCom, CMD)
            If CMD.ExecuteNonQuery() = 0 Then
                MyTrans.Rollback()
                Return 0
            End If
            CMD.Parameters.Clear()

            sSQL = []INSERT INTO Comunicados (Ano, Data, Setor, Responsavel, Autoria, Local, Referencia, Apreensao, [] _
                & []RgComunica, NumInterno) VALUES (@Ano, @Data, @Setor, @Responsavel, @Autoria, [] _
                & []@Local, @Referencia, @Apreensao, @RgComunica, @NumInterno);[]
            CMD.CommandText = sSQL
            Dim nComu As New Comunicado
            nComu.PassaParametroComunicado(Comu, CMD)
            If CMD.ExecuteNonQuery() = 0 Then
                MyTrans.Rollback()
                Return 0
            End If
            CMD.Parameters.Clear()

            CMD.CommandText = []INSERT INTO NrComunicado (NumInterno, Ano, Data) VALUES (@NumInterno, @Ano, @Data);[]
            Dim NrCom As New NrComunicado
            NrCom.PassaParametroNrComunicado(NR, CMD)
            If CMD.ExecuteNonQuery() = 0 Then
                MyTrans.Rollback()
                Return 0
            End If

            MyTrans.Commit()
            Return 1

        Catch e As Exception
            Try
                MyTrans.Rollback()
            Catch ex As MySqlException
                If Not MyTrans.Connection Is Nothing Then
                    MsgBox(ex.Message)
                End If
            End Try
            MsgBox(e.Message)
            Return 0
        Finally
            CONEXAO.Close()
        End Try

    End Function




O conhecimento como o dinheiro: quanto mais temos, mais queremos ter (Josh Billings)  


#486828 - 31/01/2019 14:01:19

KERPLUNK
RIO GRANDE DO SUL
Cadast. em:Junho/2009


Membro da equipe
Eu teria criado um overload do seu mtodo []Crud[] que retorna o comando j com os parmetros preenchidos, ou algo parecido com o que fao nos vdeos do canal.

Alm disso, voc est fazendo a coisa meio estranho. Uma transao deve ser feita commit ou rollback s depois de todos os comandos executados, tipo assim:

new transacao(){
    retornoComando1 = query1.ExecuteNonquery();
    retornoComando2 = query2.ExecuteNonquery();
    retornoComando3 = query3.ExecuteNonquery();
}
if (retornoComando1 = 0 OR retornoComando2 = 0 OR retornoComando3 = 0)
   transacao.Rollback()
else
   transacao.Commit()

Obviamente que isso acima pseudo-cdigo, mas j d pra ter uma idia. Digo isso porque notei que voc tem alguns rollback no meio do processo, isso no me parece lgico. Transao assim, todos os comandos executados dentro dela esto num s bloco, se por qualquer motivo algo deu errado, NENHUM deles gravado no banco e anula tudo. Ou seja, tudo ou nada.

_______________________________________________________________________
Virei Orculo!
The end is nigh, be ready for the nukes!


#486831 - 31/01/2019 14:40:37

DAMASCENO.CESAR
ADAMANTINA
Cadast. em:Fevereiro/2009


Por isso no encerrei rsrsrs, sempre recebendo ajuda dos amigos do frum
KERP, vou alterar seguindo sua sugesto.

Obrigado

O conhecimento como o dinheiro: quanto mais temos, mais queremos ter (Josh Billings)  


#486832 - 31/01/2019 15:27:41

FOXMAN
BARRETOS
Cadast. em:Janeiro/2001


Membro da equipe

Última edição em 31/01/2019 15:53:55 por FOXMAN

Citação:
:
Desculpem a demora em responder, estava testando as ideias sugeridas
FOXMAN, meu conhecimento em Banco de Dados pequeno, tentei criar chaves estrangeiras com os campos j existentes, que, de certa forma se repetem, mas deu erro rsrsrs
ento abandonei a ideia por enquanto, preciso e vou aprender mais sobre isso.

KERP, me baseei em sua ideia e, me parece que deu certo, preciso realizar mais testes e ver se ainda h algum erro meu, mas o resultado ficou assim

  Public Function InsereVarios(ByVal AUP As ClsAutoProced, ByVal Autor As ClsAutorComunicado, ByVal BdCom As ClsBdComunicado, Comu As ClsComunicados, ByVal NR As ClsNrComunicado) As Integer

        Dim CONEXAO As New MySqlConnection(MinhaConexao)
        CONEXAO.Open()
        Dim CMD As MySqlCommand = CONEXAO.CreateCommand
        Dim MyTrans As MySqlTransaction
        Dim RSP As Integer = 0
        MyTrans = CONEXAO.BeginTransaction()

        CMD.Connection = CONEXAO
        CMD.Transaction = MyTrans

        Try
            Dim sSQL As String
            sSQL = []INSERT INTO AutoProced (NumInterno, Ano, Matricula, Nome, Referencia, DataFalta) [] _
                & []VALUES (@NumInterno, @Ano, @Matricula, @Nome, @Referencia, @DataFalta)[]
            CMD.CommandText = sSQL
            CMD.CommandType = CommandType.Text
            Dim dAUP As New AutoProced
            dAUP.PassaParametroAutoProced(AUP, CMD)
            If CMD.ExecuteNonQuery() = 0 Then Return 0
            CMD.Parameters.Clear()

            Dim nAutor As New AutorComunicado
            CMD.CommandText = []INSERT INTO AutorComunicado (Ano, Matricula, NumInterno) VALUES (@Ano, @Matricula, @NumInterno);[]
            nAutor.PassaParametroAutorComunicado(Autor, CMD)
            CMD.ExecuteNonQuery()
            CMD.Parameters.Clear()

            sSQL = []INSERT INTO BdComunicado (Ano, Dependencia, Natureza, Local, DtFato, HoraFato, DtComunica, HoraComunica, [] _
                & [] Autor, RaioCela, Vitima, Testemunha, Apreensao, Historico, Comunicante, RgComunica, NumInterno) VALUES [] _
                & [](@Ano, @Dependencia, @Natureza, @Local, @DtFato, @HoraFato, @DtComunica,@HoraComunica, [] _
                & []@Autor, @Raiocela, @Vitima, @Testemunha, @Apreensao, @Historico, @Comunicante, @RgComunica, @NumInterno);[]
            CMD.CommandText = sSQL
            Dim nBdCom As New BdComunicados
            nBdCom.PassaParametroBdComunicado(BdCom, CMD)
            If CMD.ExecuteNonQuery() = 0 Then
                MyTrans.Rollback()
                Return 0
            End If
            CMD.Parameters.Clear()

            sSQL = []INSERT INTO Comunicados (Ano, Data, Setor, Responsavel, Autoria, Local, Referencia, Apreensao, [] _
                & []RgComunica, NumInterno) VALUES (@Ano, @Data, @Setor, @Responsavel, @Autoria, [] _
                & []@Local, @Referencia, @Apreensao, @RgComunica, @NumInterno);[]
            CMD.CommandText = sSQL
            Dim nComu As New Comunicado
            nComu.PassaParametroComunicado(Comu, CMD)
            If CMD.ExecuteNonQuery() = 0 Then
                MyTrans.Rollback()
                Return 0
            End If
            CMD.Parameters.Clear()

            CMD.CommandText = []INSERT INTO NrComunicado (NumInterno, Ano, Data) VALUES (@NumInterno, @Ano, @Data);[]
            Dim NrCom As New NrComunicado
            NrCom.PassaParametroNrComunicado(NR, CMD)
            If CMD.ExecuteNonQuery() = 0 Then
                MyTrans.Rollback()
                Return 0
            End If

            MyTrans.Commit()
            Return 1

        Catch e As Exception
            Try
                MyTrans.Rollback()
            Catch ex As MySqlException
                If Not MyTrans.Connection Is Nothing Then
                    MsgBox(ex.Message)
                End If
            End Try
            MsgBox(e.Message)
            Return 0
        Finally
            CONEXAO.Close()
        End Try

    End Function





E onde que entra as regras do negcio nessa histria ?

Uma vez que as Regras de Negcio servem para estabelecer critrios e/ou condies para que uma ao seja realizada....
Exemplificando....
Se um campo dito como DOCUMENTO(CPF ou CNPJ), no contiver 11 ou 14 digitos, e averiguado a validade desse documento, no sendo satisfatrio essa validade, nem passa da regra de negocio, retornando para o usurio o possvel erro.

Segue um exemplo de como procedo com CRUD.
Lembrando que utilizo myIsam no INNODB, ou seja no tem Transactions.

Basicamente isso.

internal bool SalvaPessoa(Pessoa pessoa, Dictionary<string, string> campos)
        {
            try
            {
                bool Opcao = false;
                string campo = string.Empty;
                string sql = []spSalvaPessoa[];
                MySqlCommand com = new MySqlCommand(sql, Conexao(conn));
                com.CommandType = System.Data.CommandType.StoredProcedure;
                foreach (var c in pessoa.GetType().GetProperties())
                {
                    foreach (var item in campos)
                    {
                        if (item.Key.ToUpper() == c.Name.ToUpper())
                        {
                            try
                            {
                                if (item.Key.ToUpper() == []Contatos[].ToUpper())
                                {
                                    string contato = string.Empty;

                                    if (Controle.Cadastros.Pessoas.Pessoa.Contatos.Count == 0)
                                    {
                                        com.Parameters.AddWithValue([]?_[] + item.Key, [][]);
                                        continue;
                                    }

                                    foreach (Contatos contatos in Controle.Cadastros.Pessoas.Pessoa.Contatos)
                                    {
                                        contato += contatos.Tipo + []|[] + contatos.Descricao + []-[];
                                    }
                                    contato = contato.Substring(0, contato.Length - 1);
                                    com.Parameters.AddWithValue([]?_[] + item.Key, contato);
                                    continue;
                                }
                                var valor = c.GetValue(Controle.Cadastros.Pessoas.Pessoa, null);
                                Util.ConverteValorToTipo(Controle.Cadastros.Pessoas.Pessoa.GetType().GetProperty(item.Key).GetMethod.ReturnType, valor.ToString());
                                //Debug.WriteLine([]_[] + item.Key);
                                com.Parameters.AddWithValue([]?_[] + item.Key, Controle.Acao.ValorParametro);
                                Controle.Acao.ValorParametro = null;
                                continue;
                            }
                            catch (Exception ex)
                            {
                                throw new Exception(ex.Message.ToString());
                            }
                        }
                    }
                }

Observe que utilizo procedimentos armazenados e no instrues SQL diretamente no codigo,
Alias no novo sistema que estou desenvolvendo no h se quer uma linha com SELECT, INSERT, DELETE, UPDATE.
Muito por que a flexibilizao de vc controlar todos os retornos, e manipular dados desejados dentro dos procedimentos armazenados sem dvida uma mo na roda, uma vez que vc pode nem precisar atualizar o sistema para alterar um determinado campo ou tipo de dados.

A unica questo ter um certo conhecimento de funes e capacidades do seu SGBD.


AHHHH, eu poderia at ter usado LINQ ou LAMBDA, mas em alguns casos eu prefiro foreach.


Grupo DotNet.Br no FaceBook

Grupo WhatsDev



#486834 - 31/01/2019 15:50:38

FOXMAN
BARRETOS
Cadast. em:Janeiro/2001


Membro da equipe
Completando....
Quando o sistema chega em SalvaPessoa(....) sinal que toda a cadeia de dados foram satisfatrio para que no haja erros de CRUD.
Porm pode haver erros de queda do servidor, e neste caso nem com Transactions ser resolvido.

Atualmente no MYSQL eu substitui o INSERT por REPLACE.
Como funciona....
Com base em um campo ID primrio, o REPLACE, faz automaticamente o UPDATE ou o INSERT, dependendo da situao.
Se vc est dando um REPLACE(123,[]fulando da silva[]), e na tabela, ja existir um ID=123, ento o registro ser apenas atualizado para 123 - fulano da silva.
Mas caso o id 123 no exista, ento ser criado o registro com id 123 com os dados do mesmo.

Bacana n, nem precisa ficar fazendo INSERT ou UPDATE.
apenas REPLACE.

FICA A DICA.......
Se vc investir um pouco mais em gerenciamento de SGBD ver que o seu codigo ficar mais enxuto e de pouca manuteno.

J relatei aqui que at as classes do meu sistema so geradas diretamente no mysql, e eu apenas copio e colo a classe com base na tabela, j criando os construtores, Mapeamento, propriedades/campos.

P.S : J ouvi a histria de um analista db que ficou rico desenvolvendo uma unica SQL que retornava dados para um relatrio de um grande sistema, e que na ocasio, a atualizao de BD e Software, custaria muito caro.....
Lgico que no era uma simples SELECT, afinal programar par SGBD to complexo quanto programar para desktop. At porque no se restringe a  apenas 4 comandos.




Grupo DotNet.Br no FaceBook

Grupo WhatsDev



#486835 - 31/01/2019 16:16:18

DAMASCENO.CESAR
ADAMANTINA
Cadast. em:Fevereiro/2009


FOXMAN, no sei se faz parte das boas prticas de programao, mas as regras de negcio fao parte no form - campos obrigatrios preenchidos - (acho que o retorno mais rpido, posso estar enganado) e parte fao ao transportar o valor para o parmetro,
nos campos que pode ser nulos, exemplo:

Citação:
  if PropriedadeData > []01/01/0001[] then
          ParametroValor(Index)=format(PropriedadeData,[]yyyy-MM-dd[])
else
          ParametroValor(Index)=string.empty
end if


Sei que estou longe de ter as boas prticas de programao, por isso uso bastante o frum para aprender com as dvidas de outros e as minhas tambm
Mas perto do cdigo que fazia antes, melhorei uns mil porcento rsrsrs.
Vou usar seu exemplo tambm para melhorar meu cdigo

Obrigado

O conhecimento como o dinheiro: quanto mais temos, mais queremos ter (Josh Billings)  


#486836 - 31/01/2019 16:25:52

DAMASCENO.CESAR
ADAMANTINA
Cadast. em:Fevereiro/2009


FOXMAN, s tirando dvidas, este exemplo que mandou, voc est usando reflection nas classes? ou o que exatamente??
achei interessante, e pretendo me aprofundar mais nesta forma de programar


O conhecimento como o dinheiro: quanto mais temos, mais queremos ter (Josh Billings)  


#486871 - 01/02/2019 22:03:04

FOXMAN
BARRETOS
Cadast. em:Janeiro/2001


Membro da equipe
Citação:
:
FOXMAN, s tirando dvidas, este exemplo que mandou, voc est usando reflection nas classes? ou o que exatamente??
achei interessante, e pretendo me aprofundar mais nesta forma de programar

Utilizo muito Reflection, Linq, Lambda...
Depois que comea a manipular e utilizar reflection vira tipo um vcio....


Grupo DotNet.Br no FaceBook

Grupo WhatsDev



 Tópico anterior Próximo tópico Novo tópico


Tópico encerrado, respostas não sao permitidas
Encerrado por DAMASCENO.CESAR em 04/02/2019 14:18:29