O tema fundamental aqui é o seguinte: E se eu tiver uma transação de dois ou mais níveis, como encaixo o Business Component?
O GeneXus tem evoluído também na questão que se refere (parece a Dilma!, rs...) à sua linguagem de programação, e em alguns pontos está claramente mais 'orientado à objetos', pois na sintaxe dos BC´s existem propriedades e métodos que claramente remetem à esse novo modelo. O lado negativo é que esse modelo, implica em maior dificuldade para aqueles que não estão acostumados com esse estilo. Então, acredito que a melhor maneira de explicar é simplesmente esquecendo-se de toda teoria envolvida e partindo para um lado mais prático da coisa.
Portanto, o que buscaremos é montar um modelo que possa ser reproduzido nas diversas situações, e sem muita teoria, e as transações escolhidas são os já tão explorados NotaFiscal, Cliente e Produto, mais especificamente a NotaFiscal que possui dois níveis.
Essa transação, como você já sabe, gera duas tabelas distintas, conectadas porque no segundo nível da transação temos o atributo NotaFiscalId, que fica meio 'oculto' na estrutura.
Portanto qualquer operação de inserção ou atualização de registros se deve levar em conta que temos duas tabelas, e era isso que tínhamos que programar no modelo, diria, 'mais tradicional' do Genexus. Sendo ainda que primeiro tinhamos que criar o registro em NotaFiscal para em seguida operar a tabela NotaFiscalProduto. Então, se fossemos inserir um registro nas duas tabelas teriamos que programar algo como:
new
NotaFiscalData = &Today
ClienteId = &ClienteId
endnewZ
for each // (autonumber)
&NotaFiscalId = NotaFiscalId
endfor
new
NotaFiscalId = &NotaFiscalId
ProdutoId = &ProdutoId
NotaFiscalProdutoQtd = &NotaFiscalProdutoQtd
endnew
Essa foi apenas uma forma simplificada de tratar a situação, cuidado não é segura, pois o for each incluído para pegar o último registro inserido, devido à caracteristica do autonumber no atributo NotaFiscalId, não é uma boa estratégia, pois teríamos problema se tivessemos um caso de concorrência de inclusão simultânea na base. Mas por outro lado o exemplo explicita uma situação que vivemos no GeneXus tradicional que é a necessidade de incluir primeiro o registro em NotaFiscal para em seguida incluir alguma coisa em NotaFiscalProduto.
Business Component de Dois Níveis
No modelo aplicado aos Business Components, as duas tabelas são vistas como apenas uma, pois não é necessário separar as operações, da mesma forma que funciona no formulário da transação. O trecho de código abaixo realiza a mesma operação do modelo anterior, sem o problema da concorrência que citamos anteriormente.¬afiscal.Load(¬afiscalId)
¬afiscal.NotaFiscalData = &Today
¬afiscal.ClienteId = &ClienteId
¬afiscal.Produto.Item(1).ProdutoId = &ProdutoQtd
¬afiscal.Produto.Item(1).NotaFiscalProdutoQtd = &NotaFiscalProdutoQtd
¬afiscal.Save()
commit
Ou seja, só pela razão da inserção ocorrer apenas em uma única operação, já é melhor que o modelo anterior. Porém o modelo tem algumas coisas estranhas a primeira vista, como por exemplo, as duas linhas abaixo.
¬afiscal.Produto.Item(1).ProdutoId
¬afiscal.Produto.Item(1).NotaFiscalProdutoQtd
Referindo-se à estrutura da Transação temos a equivalência dos elementos da seguinte forma, Produto é o subnível da transação e NotaFiscalProdutoQtd e ProdutoId são atributos do segundo nível.
E o número entre parenteses Item(1), este equivale ao item a ser inserido na nota, 1, 2, 3, ....
'update' de um item
Este trecho de código pode ser utilizado para realizer o update de um item da nota fiscal.
¬afiscal.Load(¬afiscalId)
¬afiscal.Produto.Item(&item).ProdutoId = &NovoProdutoQtd
¬afiscal.Produto.Item(&item).NotaFiscalProdutoQtd = &NovoNotaFiscalProdutoQtd
¬afiscal.Save()
commit
'delete' um item
Para remover um item da nota fiscal poderíamos programar:
¬afiscal.Load(¬afiscalId)
¬afiscal.Produto.Remove(&itemaremover)
¬afiscal.Save()
commit
Percorrendo os itens
O exemplo a seguir é útil para percorrer a lista para realizar uma operação qualquer, como a atualização dos dados. No caso, altera-se a quantidade de certo produto previamente inserido na nota fiscal. Para isso é necessário criar uma variável &item do tipo NotaFiscal.Produto. e com esta realizar uma operação for...in¬afiscal.Load(¬afiscalId)
for &item in ¬afiscal.Produto
if &item.ProdutoId = &ProdutoId
&item.NotaFiscalProdutoQtd = &NotaFiscalProdutoQtd
endif
endfor
¬afiscal.Save()
commit
Observe que a atualização ocorre na variável &item, e ao realizar o save() e commit, os dados são gravados na nota.
Chega por hoje,
Business component é um recurso indispensável, você não acha? Eu sim, e vou além, sem ele estamos perdendo tempo. Mesmo que de vez em quando temos certos enroscos pra resolver, algumas mensagens estranhas, creio que deixar a transação cuidando da inserção, atualização e eliminação dos registros nas tabelas é um bom negócio. Claro, que essa é apenas minha humilde opinião.
Tem mais exemplos em:
http://wiki.gxtechnical.com/commwiki/servlet/hwiki?Business+Component+Samples,
3 comentários:
Hola Profesor, en el caso del insert, no es necesario hacer un &NotaFiscal = new() si notafiscal.fail() ?
Gracias por compartir su conocimientos
Excelente post!
Só ficou a dúvida, e se no segundo nível eu tiver uma chave composta , consigo também pegar aquele item para fazer um update dele?
Sim. No exemplo o segundo nível da TRN já chave composta.
Postar um comentário