quinta-feira, fevereiro 03, 2005

PowerBuilder - Problemas na Migração da Versão 7 para a 9

1) Mudança no retorno do comando Retrieve
No PB 7, quando você executava Retrieve em uma DataWindow e o DataObject está inválido ( a DataWindow foi apagada ou alterada o nome), o PowerBuilder retornava 0 ( não encontrou linhas). Já no PowerBuilder 9, o comando retorna -1, que é o correto já que a DataWindow não existe.
A recomendação é que caso ocorra um caso desse, verifique se a DataWindow realmente não existe. Caso não exista, comente o código colocando usuário, data e motivo pelo qual comentou o código. Após isso, teste bem o sistema

2) Mudança no tratamento do comando ScrollToRow
No PB7, quando você executava o ScrollToRow, ele não disparava eventos como RowFocusChanged e ItemFocusChanged. No PB9, estes eventos são disparados quando você executa o comando, podendo mudar o funcionamento da sua janela, caso você tenha código nestes eventos.

3) Problemas com o comando SetTrans
O comando SetTrans não é mais aceito no PowerBuilder 9, causando cancelamento do programa.
Para resolver este problema, substitua o comando SetTrans para SetTransObject.

PowerBuilder - Roteiro de Migração da Versão 7 para a 9

* Copie a aplicação localmente na sua máquina ( isto melhorará a performance da Migração, diminuindo o tempo necessário para executar o processo)
* Crie o Workspace
* Vá na janela de New / Existing Application
* Selecione a aplicação que você deseja migrar
* Monte a Library List necessária
* Confirme o nome do Target que será criado e clique em Finish
* Aparecerá uma mensagem informando que vocÊ deverá migrar os fontes. Nesta tela, desmarque a opção de exibir mensagem de informação e obsoleto e clique em OK para iniciar a migração
* Aguarde a finalização e verifique se ocorreu algum erro na migração ( é comum aparecer várias mensagens, mas a única que não deve ser ignorada é a de erro. Quando ocorrer uma mensagem de erro, devemos analisar e corrigir o problema)
* Após a finalização, para garantir o sucesso completo da aplicação, devemos executar dois passos extras
- Full Rebuild em todas a aplicação
- Optmize em todas a PBLS

quarta-feira, fevereiro 02, 2005

PowerBuilder – Armazenando fotos em um Banco de Dados

Cada vez está sendo mais comum desenvolvermos aplicações que utilizem fotos / imagens. Abaixo está um exemplo de como Armazenar e recuperar fotos no banco de dados.
Este exemplo foi feito utilizando Orace 8.1.7 e PowerBuilder 9.2 (Build 7554)

PASSO 1 – Crie uma tabela
Crie uma tabela com um campo próprio para armazenar este tipo de arquivo (geramente chamado como campo BLOB), que pode variar de acordo com o SGBD ( SQL Server/Sybase/ASE = Image ou Text; Oracle = Long ou Long Raw ou Blob ou CLOB)
No meu exemplo, criei a seguinte tabela no Oracle:

CREATE TABLE TESTE_FOTO
( CODIGO NUMBER(2) NOT NULL,
DESCRICAO VARCHAR2(100) NULL,
EXTENSAO VARCHAR2(4) NULL,
FOTO LONG RAW NULL,
CONSTRAINT PK_TESTE_FOTO PRIMARY KEY (CODIGO))

O campo EXTENSAO foi feito para resolver um problema existente na API do Oracle 8, quando recuperamos a foto para exibição.
É recomendado que você nunca crie o campo BLOB em uma tabela a parte, pois geralmente este campo ocupa muito espaço, tornando a tabela pesada para utilizar em consultas que recuperam múltiplos registros.
Um detalhe muito interessante é que o campo de FOTO tem que ser Nulo. O que vai ser explicado no passo 2.

PASSO 2 – Criar a DataWindow de Manutenção
Crie uma DataWindow atualizável com todos os campos da tabela, exceto o campo BLOB, pois ele será tratado a parte. Por isso o campo BLOB deve ser nulo, pois a inserção de registro na tabela e feita em dois passos:
1 – Inserção dos campos normais
2 – Atualização do valor do campo BLOB

PASSO 3 – Selecionando o arquivo a ser armazenado
Insira um Picture Control na sua Datawindow, que será utilizado para exibir a imagem e crie um código que permita selecionar a imagem, como no exemplo abaixo :

string docpath, docname
integer li_rtn

//Exibe janela para selecionar o arquivo
li_rtn = GetFileOpenName("Selecione a Imagem",docpath, docname, "JPEG",+ "JPEG (*.jpg),*.jpg," &
+ "BMP (*.BMP),*.BMP,All Files (*.*), *.*", "C:\", 18)

IF li_rtn < filename=" docpath" ls_picturename =" trim(DW_1.Object.P_1.Filename)" ll_aux =" len(ls_picturename)" ll_i =" ll_aux" ll_i =" 0"> 0 then
ls_extensao = mid(ls_picturename,ll_i + 1)
else
setNUll(ls_extensao)
end if

dw_1.setitem(1,"extensao",ls_extensao)

//Salva a DataWindow
dw_1.update()

//Transforma o arquivo em um valor Blob
WF_grava_arquivo( DW_1.Object.P_1.Filename, LL_BLOB)


lblb_imagem = LL_BLOB
ll_codigo = dw_1.getitemnumber(1,"codigo")

//Atualiza o valor blog no Banco de Dados
updateblob teste_foto
set foto = :lblb_imagem
where codigo = :ll_codigo;


//Finaliza a transacao
commit;


Código da função WF_GRAVA_ARQUIVO
wf_grava_arquivo (string as_arquivo, ref blob lblob_final);//verifica se o arquivo já existe, se existir, realiza o updade, caso contrario, realizar o insert
long ll_row, ll_codigo, ll_file, ll_tam
blob lblob_arquivo

//ll_codigo = long (sle_1.text)

//Carrega o arquivo
ll_file = FileOpen ( as_arquivo , StreamMode! , Read! , LockRead!)
if ll_file = -1 then
messagebox("Erro","Ocorreu um erro na abertura do arquivo",stopsign!)
return
end if

lBlob_final = blob('')
ll_tam = fileread(ll_file, lblob_arquivo)


do while (ll_tam > 0)
lBlob_final = lBlob_final + lblob_arquivo
ll_tam = fileread(ll_file, lblob_arquivo)
loop

fileclose(ll_file)


PASSO 5 – Neste passo iremos recuperar o arquivo do banco de dados e exibi-lo na DataWindow.
No SQL Server e Sybase, basta incluir um controle “Large binary/text Database Ole Object” e prencher as informações corretas (Na dúvida, consulte o Help do PowerBuilder).
Mas, a solução acima não funciona no Oracle, pois existem alguns problemas com este controle, onde os dados não são recuperados.
Para resolver este problema, eu tive que criar a seguinte solução
1 – Recupero o campo BLOB para uma variável BLOB
2 – Limpo os arquivos temporários existentes. Para isso, armazeno os nomes dos arquivos temporários gerados em um XML
3 – Crio o arquivo temporário a partir da variável BLOB. Por este motivo, eu armazeno a extensão do arquivo na hora de gravar, evitando conflitos de tipos de arquivos. Neste ponto, também armazeno o nome do mesmo no XML, para limpeza no futuro.
4 – Utilizando um Picture Control na DataWindow, exibo o arquivo temporário armazenado.

Abaixo está o código utilizado para fazer este procedimento :

long ll_rowcount
long ll_codigo, ll_file, ll_row
blob lblb_imagem, lBlob_final, lblob_arquivo
string ls_imagem, ls_path
datastore vld_datastore

//Configura DataStore de Gerenciamento de arquivos temporários
vld_datastore = create datastore
vld_datastore.dataobject = 'd_arquivos_temporarios'

ll_codigo = long(sle_1.text)

//Recupera os Registros
ll_rowcount = dw_1.retrieve (ll_codigo)

//Se existir registro, vai para o tratamento do Blob
if ll_rowcount > 0 then
//Seleciona o campo Blob
selectblob foto
into :lblb_imagem
from teste_foto
where codigo = :ll_codigo;

//Importa os dados do arquivo XML de controle de arquivos temporarios
vld_datastore.importfile(XML!,'C:\tmpfoto.xml')

//Apaga todos os arquivos temporarios existentes na máquina
for ll_row = vld_datastore.rowcount() to 1 step -1
filedelete(vld_datastore.getitemstring(ll_row,"filename"))
vld_datastore.deleterow(ll_row)
next

//gera um arquivo temporario, com a extensao original
ls_path = "c:\tmpfoto" + string(today(),"yyyymmdd")+string(now(),"hhmmssffff")+"."+dw_1.getitemstring(1,"extensao")

//Grava o nome do aquivo temporario no XML de controle
ll_row = vld_datastore.insertrow(0)
vld_datastore.setitem(ll_row,"filename",ls_path)
vld_datastore.saveas( "C:\tmpfoto.xml", XML!,true )


//Carrega o arquivo
ll_file = FileOpen ( ls_path , StreamMode! , write! , Lockwrite!, Replace!)
if ll_file = -1 then
messagebox("Erro","Ocorreu um erro na abertura do arquivo",stopsign!)
return
end if

//Lê o blob e grava um arquivo
lBlob_final = lblb_imagem

do while (len(lBlob_final) > 0)
lblob_arquivo = blobmid(lBlob_final,1,32000)
filewrite(ll_file,lblob_arquivo)
lBlob_final = blobmid(lBlob_final,32001)
loop

fileclose(ll_file)

//Exibe o arquivo temporario
DW_1.Object.P_1.Filename=ls_path


messagebox("Sucesso","Arquivo recuperad com sucesso!")
end if



Boa sorte!!!!