Introdução
Em uma aplicação mestre detalhe um registro mestre é exibido na tela e, abaixo deste, os seus detalhes.
Geralmente nesse tipo de aplicação temos uma relação do tipo 1 para n entre mestre e detalhe.
Por exemplo, em um carrinho de compras temos uma relação do tipo 1 para n entre o carrinho e seus itens, como mostra a Figura 1.
Ao enviar os dados desse carrinho, o que pode dar errado? Imagine que os dados são gravados sequencialmente, como uma fila, assim como vemos na Figura 2. Agora, considere que após gravar o primeiro item, ocorra uma falha de comunicação com o banco de dados, terminando a operação com um erro.
Neste caso a compra será registrada pela metade, pois o primeiro item já havia sido salvo.
Um primeiro passo para evitar esse tipo de problema é fazer com que todos os comandos sejam executados dentro de uma mesma transação. Assim, garantimos a atomicidade da operação e para a aplicação todos os passos para a gravação do carrinho serão um único processo indivisível.
Quando usamos uma transação ou todos os registros são gravadas ou nenhum deles é.
Um segundo passo para evitar problemas em uma aplicação mestre/detalhe é se manter atento sobre a duplicação de código.
Em um relacionamento 1 para n, o que acontece quando desejamos remover do banco de dados a entidade mestre? Nesse caso, devemos também remover os detalhes para que os registros não fiquem órfãos, detalhes que apontam para mestres anteriormente apagados.
Entretanto, também é comum necessitarmos apagar o mestre, quando os detalhes são completamente removidos do banco de dados, evitando assim que hajam mestres sem detalhes.
Onde colocar, então, o código responsável por desfazer o relacionamento entre o mestre e o detalhe? Deixar que esse trecho de código fique repetido no projeto não é uma boa ideia.
Uma solução é usar o padrão de projetos DAO. Nesse cenário, temos uma classe responsável pelas ações de CRUD na tabela mestre e outra para a tabela de detalhes. Em uma operação de deleção, basta fazer com que todos os itens sejam removidos primeiro e, logo após, o registro mestre.
Uma vez que essas ações sempre devem ser feitas em sequência, também criamos uma classe, geralmente chamada de serviço, que execute esses passos.
O serviço é responsável por executar esses passos, em uma mesma transação, garantindo assim a sua atomicidade.