none
Dúvida sobre Insert em 3 tabelas com controle de transação - C# e SQL Server RRS feed

  • Pergunta

  • Olá amigos do Fórum. 

    Estou desenvolvendo uma aplicação de controle de estoque em 3 camadas (AcesssoDados, Negocios, ObjetoTransferencia e Apresentacao) bem simples pois sou iniciante em C#. Minha base no SQL Server
    possui 3 tabelas ()Pesssoa, PessoaFisica e Cliente) juntamente com 3 procedures individuais para dar um insert em cada tabela.

    O problema é que quando eu dar um insert no form de cadastro de clientes, ele terá que chamar 3 funções (InserirCliente, InserirPessoaFisica e InserirPessoa) separadamente
    de cada classe da camada de negocios e precisava usar um controle de transação no C# para assegurar que o insert será dado nas 3 tabelas e dar um rollback caso ocorra alguma 
    falha ao inserir em uma das tabelas.

    Estou com dificuldades em usar o SqlTransaction  pois ele pede conexão e cmd, mas isso fica em outra camada e se eu implementar isso no form 
    ficará estranho, meio repetido o código e não sei se é o correto...

    Postei meu projeto de C# no seguinte link: https://onedrive.live.com/?cid=40838E65B9F8787E&id=40838e65b9f8787e%21120

    Alguém sabe como me ajudar a resolver este problema?

    Obrigado :)
    quarta-feira, 15 de abril de 2015 00:30

Respostas

  • Boa Tarde Jalber, de buenas?

    Tem algumas coisas diferentes que você pode tentar. Uma delas seria utilizar um TransactionScope, que cria um controle transacional da base de dados a nível de aplicação, garantindo a integridade dos seus dados durante a operação e só comitando os dados a base de dados após um commit por parte da aplicação. Segue abaixo a página de documentação da classe System.Transactions.TransacionScope().

    System.Transactions.TransactionScope

    Mas como o Renato apontou, não seria a solução mais interessante, principalmente se você migrar em algum futuro próximo ou distante para uma versão web. A quantidade de requisições à base de dados e o custo para a base de executar três procedures, mesmo que já tenham seu plano de ação compilado, vai ser maior do que executar uma única procedure fazendo uma única requisição.

    O que você pode fazer, dada a forma como você desenvolveu sua classe que faz as chamadas as procedures e passa os parâmetros, é se utilizar de um "User Defined Type" na sua base dedados. Você pode criar um tabletype em sua base de dados, espelhando as propriedades dos seus objetos na forma de tabelas. Um UserDefinedType é read only, mas pode ser passado como parâmetro em uma procedure.

    Do lado da aplicação, você criaria uma DataTable e atribuiria ao seu DataTable os parâmetros do objeto que vai passar para a procedure. Do lado do SQL Server, você criaria uma procedure que recebe três parâmetros, cada um sendo um user defined type que é uma tabela com os parâmetros que você precisa persistir na base de dados para cada um dos registros que está criando.

    Segue um breve artigo do technet que explica como criar um table type para ser utilizado como user defined type no SQL Server 2008:

    User Defined Table Types

    Espero poder ter ajudado!

    Aquele abrass,

    sexta-feira, 17 de abril de 2015 17:43

Todas as Respostas

  • Jalber,

    Eu tentaria fazer uma única procedure, centralizando todo este processo de inclusão. Desta maneira, poderia deixar a cargo da própria procedure algum controle transacional e evitaria vários acessos à base de dados (o que é particularmente interessante, sobretudo se este sistema migrar para a Web).

    Espero ter ajudado.

    Abs

    quarta-feira, 15 de abril de 2015 01:09
  • Obrigado pela contribuição Renato.

    Mas o problema é que na aplicação tenho 3 funções distintas de 3 classes(Pessoa, PessoaFisica e Cliente) Inserir diferentes usando uma única procedure... Não sei como implementar isso.

    quarta-feira, 15 de abril de 2015 10:13
  • Boa Tarde Jalber, de buenas?

    Tem algumas coisas diferentes que você pode tentar. Uma delas seria utilizar um TransactionScope, que cria um controle transacional da base de dados a nível de aplicação, garantindo a integridade dos seus dados durante a operação e só comitando os dados a base de dados após um commit por parte da aplicação. Segue abaixo a página de documentação da classe System.Transactions.TransacionScope().

    System.Transactions.TransactionScope

    Mas como o Renato apontou, não seria a solução mais interessante, principalmente se você migrar em algum futuro próximo ou distante para uma versão web. A quantidade de requisições à base de dados e o custo para a base de executar três procedures, mesmo que já tenham seu plano de ação compilado, vai ser maior do que executar uma única procedure fazendo uma única requisição.

    O que você pode fazer, dada a forma como você desenvolveu sua classe que faz as chamadas as procedures e passa os parâmetros, é se utilizar de um "User Defined Type" na sua base dedados. Você pode criar um tabletype em sua base de dados, espelhando as propriedades dos seus objetos na forma de tabelas. Um UserDefinedType é read only, mas pode ser passado como parâmetro em uma procedure.

    Do lado da aplicação, você criaria uma DataTable e atribuiria ao seu DataTable os parâmetros do objeto que vai passar para a procedure. Do lado do SQL Server, você criaria uma procedure que recebe três parâmetros, cada um sendo um user defined type que é uma tabela com os parâmetros que você precisa persistir na base de dados para cada um dos registros que está criando.

    Segue um breve artigo do technet que explica como criar um table type para ser utilizado como user defined type no SQL Server 2008:

    User Defined Table Types

    Espero poder ter ajudado!

    Aquele abrass,

    sexta-feira, 17 de abril de 2015 17:43
  • Obrigado pela ótima dica S.Pelaquim...

    Vou pesquisar sobre o assunto... :)

    sábado, 18 de abril de 2015 15:45