|
|
 |
| Tecnologias :: Visual FoxPro |
 |
|
| |
|
| Armadilhas do Projeto de Banco de Dados |
Por Victor Campos, artigo originalmente publicado na revista UTMag/RapoZine. |
Já faz alguns meses desde meu último artigo no Universal Thread. Para aqueles pensando onde foi que estive escondido, estava na verdade colocando esforço total para completar os testes requeridos para obter minha certificação MCSD. Adicionamente, eu também estava preparando minhas sessões para a EssentialFox, que se tornou uma conferência fantástica. Se você a perdeu, recomendo fortemente que não a perca no próximo ano. E se você pensa que eu não tinha coisa suficiente para fazer, ainda tive que atender meus clientes. É um prato cheio!
Nos últimos três meses estive involvido na conversão de um projeto, movendo os dados de um banco de dados Visual FoxPro para um banco de dados SQL Server. Embora o banco de dados do VFP tenha poder de performance suficiente e tenha carregado os dados da empresa por muitos anos, ele infelizmente chegou ao ponto onde não mais manteria os dados, devido à limitação de tamanho de 2 GB para cada tabela.
A loja involvida com esta conversão tem uma excelente equipe de desenvolvedores VFP - provavelmente a melhor que já vi até hoje. A aplicação é construída em uma maneira extremamente flexível e bastante robusta - eu posso honestamente dizer que eles conhecem Programação Orientada a Objeto. A despeito do fato de que a equipe é experiente (talvez muito experiente) que quando vem para o VFP eles gerenciam muito e capturam a si mesmos em um canto que os força a recurar e retrabalhar algumas idéias. Estas idéias estão no projeto do banco de dados. Os desenvolvedores podem fazer o VFP dar saltos de trampulim, parar de ponta-cabeça e girar mas isto nem sempre significa flexibilidade. Então, todos, de iniciantes a experts, podem se beneficiar deste artigo. Eu não estarei cobrindo o "Como projetar um banco de dados", porque eu acredito que o projeto de banco de dados está a cargo do artista. Entretanto, eu irei cobrir as armadilhas do projeto de seu banco de dados.
O aspecto mais dificil do projeto de banco de dados é permitir flexibilidade e escalabilidade. Projete seu banco de dados de maneira que ele possa facilmente se adaptar às alterações nos requerimentos de negócios já criados, de modo a adaptar-se a qualquer necessidade encontrada. Uma das técnicas mais utilizadas para flexibilidade no acesso aos dados no VFP é usando views atualizáveis. Basicamente, as definições de uma view são persistentemente armazenadas em instruções SQL que resultam em uma view atualizável. Usado apropriadamente, isto permitirá a você trocar entre plataformas de banco de dados com pouco ou nenhum esforço.
Vamos falar sobre como views podem dar a você flexibilidade. Para este exemplo eu usarei o banco de dados que vem com o VFP, localizado no diretório HOME(2)+"\Data". A seguinte view foi criada usando o View Designer.
CREATE SQL VIEW lv_customer AS;
SELECT *;
FROM testdata!customer;
WHERE Customer.cust_id = ?vp_Cust_ID
Outras propriedades são configuradas mas não mostradas aqui. Agora quando eu acesso esta view eu posso chamá-la usando a seguinte instrução:
USE lv_customer IN 0 ALIAS v_customer SHARED
Obviamente, visto que estou usando uma view parametrizada eu receberei uma caixa de diálogo me pedindo para inserir o valor de vp_Cust_ID. Entretanto, esta view agora tem que colocar uma camada de abstração entre o código e os dados. Então, isto levanta uma questão: "Como isto irá realmente criar uma aplicação flexível?" Cuidadosamente olhando para a declaração USE você percebe que adicionei a clásula ALIAS, então quando a view estiver sendo usada ela irá abrir com o alias v_customer, a despeito do fato de que estarei usando uma view de nome lv_customer. Em qualquer momento você pode decidir usar uma view remota para acessar esta view para acessar um banco de dados como o SQL Server, Oracle ou mySQL e nomeá-la rv_customer. Visto que você está usando v_customer através de sua aplicação o único trecho de código que precisa ser alterado é a declaração USE:
USE rv_customer IN 0 ALIAS v_customer SHARED
Visto que o VFP é uma linguagem OOP e todos estã usando Objetos de Negócios tudo que você precisa é alterar a linha de código e você estará capacitando sua aplicação para usar dados remotos. O que é extraordinário sobre isto? Pense sobre como você escreveu uma aplicação monolítica que automaticamente passou para Cliente/Servidor com alterações mínimas em seu código.
Acredite ou não, usar esta técnica pode algumas vezes ter seu preço Em geral, o desenvolvedor escreve código para encontrar solução para algum problema. Eles também fazem um esforço incrível para manter a aplicação flexível. A despeito dos esforços que eles colocam, eles sempre fazem com que fiquem presos em algum canto. A view mostrada no exemplo anterior é muito simples de causar armadilhas reais. Mas continue lendo pois conseguiremos algumas belas instruções SQL reais que tornam o VFP extremamente flexível, mas ainda necessitando reescrever coisas quando tentarmos passar para servidores de banco de dados, como SQL Server, Oracle ou mySQL.
Usando funções do VFP e UDF's
Ser capaz de servir seus dados em um formato que é pronto para o uso algumas vezes é desejado pelos desenvolvedores. Tome por exemplo a seguinte instrução SQL:
SELECT ALLTRIM(contact)+', '+ALLTRIM(title) as name, ;
ALLTRIM(address)+', '+ALLTRIM(city)+;
', '+ALLTRIM(region)+ ' '+;
ALLTRIM(postalcode) as address;
FROM customer;
WHERE country='USA'
Esta específica declaração mostraria um resultado como este:
Embora isto seja extremamente útil em grids e listas drop-down, você criou uma instrução SQL que somente trabalhará no VFP. Atualmente, você somente teria que trocar o comando ALLTRIM() para o RTRIM() no MS SQL. Entretanto, o que dizer para aqueles que não estiverem migrando para o MS SQL. Não estou acostumado com o PL do Oracle, então não sou capaz de dizer as diferenças involvidas em fazer esta view trabalhar com Oracle. A maneira para tornar esta instrução SQL reutilizável através de várias plataformas de banco de dados é selecionando os campos específicos que você precisa para mostrar mostrar, e usando o designer visual do VFP para unir e concatenar os campos.
Usando Aspas duplas
A flexibilidade do VFP pode algumas vezes permitir ao programador criar instruções SQL que são completamente inválidas com outros motores de banco de dados compatíveis com o ANSI SQL 92. Tome pode exmplo o uso de aspas duplas. No VFP, as seguintes declarações são as mesmas, enquanto que o uso de aspas duplas é inválido no MS SQL Server:
SELECT * from employee WHERE first_name = 'Tim'
SELECT * from employee WHERE first_name = "Tim"
Imagine gastar muitos anos escrevento todas as suas instruções SQL para usar aspas dubplas e quando chega a hora de migrar seus dados para o MS SQL Server ou Oracle - você terá de gastar várias semanas alterando todas as suas instruções SQL para usar aspas simples. Minha sugestão seria usar aspas simples desde o início.
Quando usar o sinal de igual e quando usar a cláusula LIKE
Isto talvez seja o mais rude para lidar quando chega ao VFP. As seguintes instruções SQL darão o mesmo resultado no VFP:
SELECT * from 'employee' WHERE first_name = 'A'
SELECT * from 'employee' WHERE first_name LIKE 'A%'
No MS SQL Server e Oracle, somente a segunda declaração SQL darão o resultado desejado. A primeira resultará em retornar registros somente com um "A" no campo first_name. Então o que você faz em tal situação? Minha sugestão é usar a técnica da segunda instrução SQL sempre que possível. No caso de estar procurando por um nome específico você pode tentar brincar com as configurações de SET EXACT do VFP enquanto executa a primeira instrução SQL para alcançar o resultado desejado. Na maioria dos casos eu tenho sempre visto o uso da primeira técnica no lugar da segunda técnica.
Macro-expansões
Macro-expansões têm sido o coração da flexibilidade do VFP. É uma infelicidade que isto somente se aplica ao VFP. Tome, por exemplo, o seguinte trecho de código:
cStateList = ['ID','WY','OR','MT','WA']
SELECT * from customer WHERE region in(&cStateList)
Internamente, o VFP traduz isto para:
SELECT * from customer WHERE region in('ID','WY','OR','MT','WA')
Novamente, infelizmente a macro-expansão somente funciona no VFP. Uma vez migrado, torna-se inútil em sua aplicação. Entretanto, as boas notícias é que você pode ainda usar SQL Pass-Through se você necessita deste tipo de flexibilidade. Para usar isto no MS SQL Server ou Oracle você pode escrever o seguinte trecho de código:
cStateList = ['ID','WY','OR','MT','WA']
lcSQL = [SELECT * ] + ;
[from customer ] +;
[WHERE region in(] + cStateList + [)]
lnConn = SQLConnect('YourConnectionName')
lnResults = SQLEXEC(lnConn,lcSQL)
Este trecho nos levou a tópicos que estão além do escopo deste artigo - mas eu gostaria de dizer que sempre existirão situações onde você não poderá ter o melhor de ambos os mundos, não importa quão duro você tente se manter ao ANSI SQL 92. Quando este for o caso você pode sempre usar o SQL Pass-Through.
O VFP suporta o ANSI SQL 92?
O VFP suporta o ANSI SQL 92 mais do que algumas pessoas pensam. O Engine SQL do VFP foi projetado para suporta a habilidade de facilmente cruzar plataformas de banco de dados com pouco ou nenhum esforço. Lembra-se que pouco tempo atrás você deveria manter-se longe de UDF´s e funções específicas do VFP? Então como você pode ficar alheio a elas? A maioria dos desenvolvedores VFP estão acostumados a escrever instruções SQL como:
SELECT * FROM customer WHERE ISNULL(fax)
Esta declaração trabalha muito bem, e é capaz de ser executada em várias plataformas de bancos de dados.
SELECT * FROM customer WHERE fax IS NULL
Executando Consultas contra outras Consultas
Outro engano comum que eu vejo com sofware houses VFP é que os desenvolvedores sempre criarão instruções SQL que utilizam os resultados de outras instruções SQL, bem como tabelas. Por exemplo:
SELECT * from orders WHERE order_amt < 100 INTO CURSOR cheaporders
SELECT Company, Contact, to_name, to_address;
FROM customer INNER JOIN cheaporders ON customer.cust_id=cheaporders.cust_id;
WHERE country<>'USA';
Order by to_name
É desafortunado que uma vez que esta instrução SQL está acessando dados em um servidor remoto, você não mais será capaz de unir cursores e tabelas. Recomendações para isto são difíceis e não irei me preocupar em tratá-las aqui - tudo que posso dizer é tentar ficar longe deste tipo de instruções SQL. Entretanto, você pode estar preso a ter de fazer algo deste tipo - um cavalheiro de nome Sergey Berezniker no UT foi suficientemente generonoso em mostrarme uma forma de contornar isto usando SPT:
SELECT Company, Contact, to_name, to_address FROM customer INNER JOIN
(SELECT * from orders WHERE order_amt < 100) cheaporders ON customer.cust_id=cheaporders.cust_id
WHERE country<>'USA' Order by to_name
Bastante surpreendente, isto é executado mais rápido no SQL Server do que se executar duas consultas separadas no VFP. Isto é chamado usando um cursor derivado e é muito útil. Novamente, tenha em mente que você não pode usar isto no VFP e nem pode unir cursores com tabelas no SQL Server.
Usando Transações
Transações no VFP são bastante similares àquelas no SQL Server com alguns detalhes e algumas diferenças. Se você estiver usando uma simples tabela em uma transação você pode apostar que coisas funcionarão de forma muito parecida a um ambiente cliente/servidor. É quando você começa a aninhar transações que você começa a encontrar problemas.
Transações aninhadas no VFP enquanto estiver usando views locais são bastante simples:
BEGIN TRANSACTION
lParentResult = TABLEUPDATE(parent_view)
IF lParentResult
BEGIN TRANSACTION
lChildResult = TABLEUPDATE(child_view)
IF lChildResult
END TRANSACTION
ELSE
ROLLBACK
ENDIF
IF lChildResult
END TRANSACTION
ELSE
ROLLBACK
ENDIF
ELSE
rollback
ENDIF
Este mesmo trecho de código não funcionaria se você estivesse usando views remotas. Uma das coisas a se lembrar quando estiver usando views remotas é que transações são implícitas. Isto significa que toda vez que você executar um TABLEUPDATE() o SQL Server começará a submeter ou fazer o rollback de suas próprias transações. Para fezê-las de forma explícita você precisa deixar o SQL Server que você tem a intenção de usar transações e terminará ou rolará as transações manualmente. Convencionando-se que suas views estarã usando a mesma conexão, você pode usar o seguinte trecho de código:
nHandle = CURSORGETPROP("ConnectHandle","parent_view")
SQLSETPROP(nHandle,"Transactions",2) && Configura para transações manuais
BEGIN TRANSACTION
lParentResult = TABLEUPDATE(parent_view)
IF lParentResult
BEGIN TRANSACTION
lChildResult = TABLEUPDATE(child_view)
IF lChildResult
END TRANSACTION
ELSE
ROLLBACK
ENDIF
IF lChildResult
END TRANSACTION
SQLCOMMIT(nHandle)
ELSE
ROLLBACK
SQLROLLBACK(nHandle)
ENDIF
ELSE
Rollback
SQLROLLBACK(nHandle)
ENDIF
Então há algumas funcionalidades que você perde quando migra? Você definitivamente perde o uso de _TALLY. Devido a características de dados remotos que o VFP fornece e não mais preenche o valor de _TALLY, então não pode ser mais usado.
Dependendo das configurações da view remota você também perderá a habilidade de usar RECCOUNT(). Por padrão, o VFP reune dados de tabelas remotas de uma forma "coforme necessário". É claro, se sua aplicação depende de funcionalidades de contar registros, existem algumas configurações que podem ser modificadas para acomodar tais características.
Enquanto estiver usando SPT você não mais poderá especificar o nome do cursor a ser usado na instrução SELECT. Ele agora se torna um dos parâmetros no comando SQLEXECT(). Isto coloca um amortecedor quando estiver tentando unir resultados de instruções SQL e tabelas remotas.
Conclusão
Embora o Visual FoxPro é um ótimo banco de dados para pequenas, médias e mesmo algumas grandes empresas, a hora chega em que o negócio precisará de uma solução para alta capacidade de armazenamento. Como eu disse antes, o engine de banco de dados do VFP é ótimo, é rápido e é flexível - só é uma infelicidade que o tamanho-limite de uma tabela seja de 2 GB, e o forçará a migrar para um servidor de banco de dados. Isto é mau? Eu diria que não. O Visual FoxPro trabalha muito bem com a conexão com servidores de banco de dados como o SQL Server, Oracle e mySQL. Não há nada no seu caminho se quiser utilizar o VFP como front-end para uma grande solução empresarial utilizando um servidor de banco de dados. Tenha em mente que você pode sempre manter-se usando ANSI SQL 92 tanto quanto for possível para evitar ser capturado em um canto que o forçará a re-escrever muitas de suas idéias muito bem pensadas.
Victor Campos é Presidente da Options Software Consulting - ele assessora empresas a encontrar soluções de softwares para o mundo real através do uso de objetos de negócios. Qualquer um interessado em software customizado, treinamento ou aconselhamento por favor contate-o no endereço de email listado abaixo. Ele tem trabalhado com o FoxPro desde a versão 1.02 para DOS e continua usando o FoxPro desde então. Recentemente, ele conquistou o status de MCSD passando nos exames solicitados, e está atualmente trabalhando em direção à certificação MCDBA. Qualquer questão a respeito deste artigo, projeto ou questões em geral podem ser encaminhadas para victor@options-sc.com.
topo
|
|
 |