32

Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

Embed Size (px)

Citation preview

Page 1: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um
Page 2: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um
Page 3: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

editorial

03

sumário

THE CLUBAv. Profº Celso Ferreira da Silva, 190

Jd. Europa - Avaré - SP - CEP 18.707-150Informações: (14) 3732-3689

Suporte: (14) 3733-1588 - Fax: (14) 3732-0987

Internethttp://www.theclub.com.br

Cadastro: [email protected]: [email protected] Informações: [email protected]

DúvidasCorrespondência ou fax com dúvidas devem

ser enviados ao - THE CLUB, indicando “Suporte”.

OpiniãoSe você quer dar a sua opinião sobre o clube

em geral, mande a sua correspondência para a seção “Tire sua dúvida”.

ReproduçãoA utilização, reprodução, apropriação,

armazenamento em banco de dados, sob qualquer forma ou meio, de textos, fotos e outras criações intelectuais em cada

publicação da revista “The Club Megazine” são terminantemente proibidos sem autorização

escrita dos titulares dos direitos autorais.

Impressão e acabamento:HIPERGRAF Indústria Gráfica

Tel.: (14) 3641-1665 - Cep 17340-000Rua Francisca A. Pereira Borges, 436

Barra Bonita - Vila São CaetanoTiragem: 5.000 exemplares

Copyright The Club Megazine 2007

Diretor TécnicoMauro Sant’Anna

Colaboradores Mauto Sant´Anna

Delphi é marca registrada da Borland International, as demais marcas citadas são registradas

pelos seus respectivos proprietários.

- Editorial .................................................................................................... 03

- dbExpress: Tratamento Centralizado de Erros ....................................................... 04

- Usando KEEPALIVE-sockets para detectar ................................................ 08

e liberar conexões do InterBase e Firebird travadas,

ou como prevenir o erro 10054/104

- Acessando o FireBird via Delphi 8 .NET ........................................................... ................ 12

- Utilizando o controlador de versões ........... .......................................................... 23

EditorialJá se vão praticamente 15 anos de existência do The Club,

prestando suporte técnico à inúmeros programadores de todo o Brasil. Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas coisas relacionadas ao Visual Studio.

Apesar de vários problemas enfrentados em todos esses anos, posso afirmar que foi um prazer fundar, trabalhar e comandar essa empresa. Sem dúvida alguma foi aqui que vivi minhas maiores alegrias. Quero de coração agradecer a todos aqueles que me acompanharam em todos esses anos, clientes, colaboradores e amigos, meu muito obrigado.

Na edição deste mês, temos vários artigos interessantes, dos quais posso adiantar que vocês gostarão do “dbExpress: Tratamento Centralizado de Erros” e “Acessando o Firebird via Delphi 8.NET” do Alessandro Ferreira, e a matéria principal, do Fábio Câmara, “Utilizando o Controlador de Versões”, muito útil para quem faz programas com 2 ou mais pessoas.

Espero que gostem!

Celso Jefferson Messias Paganelli

Page 4: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

dbexpress

04

Introdução

Neste artigo irei abordar um tema muito solicitado aqui no suporte The Club, ou seja, como implementar um tratamento de erros trabalhando com a a dbExpress e consequentemente com o ClientDataSet, onde demonstraremos como tratar erros no lado cliente e também erros providos pelo servidor de banco de dados.

Tratando erros no cliente

Quando menciono: tratamento de erros no cliente, refiro-me ao fato de efetuar validações antes mesmo do registro ser postado ao banco de dados, com isso, evita-se o tráfego em rede e conseqüentemente temos uma resposta mais rápida à repassar ao usuário. Um ótimo local para efetuarmos este tipo de validação é o evento OnPostError do componente ClientDataSet, visto o mesmo ser acionado automaticamente mediante qualquer violação verificável pelo ClientDataSet.

A fim de economizar código, podemos implementar uma função genérica e chamar esta função dentro do OnPostError e com isso, caso haja necessidade de alguma alteração ou nova validação, bastará alterar esta função que o evento irá tratar os erros com base nas novas regras definidas. Na listagem 1, apresento um código simples que utilizo no evento OnPostError dos ClientDataSet de meus aplicativos:

function CommonPostError(DataSet: TData-Set; E: EDatabaseError): TDataAction;var Msg: String;begin Msg := E.Message; if Pos(‘MUST HAVE A VALUE’, UpperCase(E.Message)) > 0 then begin Msg := Copy(Copy(E.Message,Pos(‘’’’,E.Message)+1,Length(E.Message)),1,Pos(‘’’’,Copy(E.Message,Pos‘’’’,E.Message)+1,Length(E.Message)))-1); Msg := Format(‘O campo %s deve ser

preenchido!’, [Msg]); end else if Pos(‘KEY VIOLATION’, UpperCase(E.Message)) > 0 then begin Msg := Format(‘Registro duplicado em %s’, [DataSet.Name]); end else if Pos(‘FIELD VALUE REQUIRED’, UpperCase(E.Message)) > 0 then begin Msg := Format(‘Existem campos obrigatórios não preenchidos, veri-fique!’, [DataSet.Name]); end; ShowMessage(Msg); Result := daAbort;end;

Listagem 1 - Função CommonPostError

Na listagem 2, demonstro como utilizar a função CommonPostError no evento OnPostError de um ClientDataSet:

procedure TfmCadCanais.cdsCanaisPostError(DataSet: TDataSet; E: EDatabaseError; var Action: TDataAc-tion);begin Action := CommonPostError(DataSet, E);end;

Listagem 2.

Observe que o evento OnPostError possui três parâmetros:

DataSet = Representa o componente ClientDataSet em edição.

Page 5: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

dbexpress

05

E = Traz as informações a respeito do erro, como por exemplo, a men-sagem de erro.

Action = Qual a ação que será tomada mediante o erro ocasionado, podendo receber como valor:

daFail : Aborta a operação e apresenta a mensagem de erro.

daAbort : Aborta a operação e não apresenta a mensagem de erro.

daRetry : Repere a operação.

Em nossa função estamos utilizando como retorno daAbort, pois iremos abortar a operação e apresentar uma mensagem personalizada e não a mensagem original de erro sugerida pelo EDatabaseError. Um outro aspecto importante, é que a classe EDatabaseError não retorna um código de erro e sim somente a mensagem de erro e, será com base na mensagem de erro que iremos personalizar a informação à ser repassada ao usuário, como exemplo:

MUST HAVE A VALUE O campo X deve ser preenchido

KEY VIOLATION Registro duplicado

FIELD VALUE REQUIRED Existem campos obrigatórios não preenchidos, verifique!

Tratando erros retornados pelo Servidor

Mesmo efetuando o tratamento de erros no evento OnPostError, existem muitas validações (como exemplo: Integridade Referencial) que são efetuadas no banco de dados e, dessa forma não passam pelo evento OnPostError, lembrando que estes erros serão apresentados apenas após a execução do método ApplyUpdates, visto que até então, os dados estão em cache local no Cliente.

Ainda sobre o método ApplyUpdates, gostaria de ressaltar que o mesmo não gera uma exceção, isso mesmo, se você chamar este método e algum erro de validação ocorrer no servidor, nenhuma exceção será levantada e os dados não serão efetivados no banco de dados. Você pode estar se per-guntando o por que disso e achando até um pouco estranho. Na realidade, como é de conhecimento de todos, o ApplyUpdates recebe um parâmetro do tipo inteiro, o qual muita gente utiliza sem saber exatamente sua finali-dade. Este parâmetro indica o número máximo de erros suportados durante o processo de atualização, visto que, devido ao mecanismo de cache, você pode ter N registros em memória e efetuar apenas um ApplyUpdates para confirmar todo o processamento.

Dentro deste contexto, qual o valor correto à ser informado ao Ap-plyUpdates? Isso irá depender de suas necessidades! Vamos expor algumas situações:

a. Supondo que você possua N registros em cache e no momento da atualização necessite que: todos os registros sejam gravados com sucesso ou do contrário, nenhum deles seja efetivado no banco de dados, o valor a

ser informado será “0”, ou seja, você não admite nenhum erro no processo de atualização.

b. Supondo que você possua N registros em cache e estes registros não tenham nenhum tipo de integridade entre si e deseje gravar o que conseguir, ficando apenas os registros com problemas no cache, o valor a ser informado será “-1”.

Como mencionei anteriormente, se alguma violação ocorrer durante o processo de atualização, nenhuma exceção será levantada, visto que o mecanismo Provider/Resolver permite o tratamento de falhas no processo de atualização registro a registro utilizando o evento OnReconcileError do ClientDataSet, dessa forma, qualquer erro que seja gerado neste processo, poderemos verificar através do evento OnReconcileError.

Novamente, vamos implementar uma função genérica para tratamento dos erros, confira a listagem 3:

function CustomReconcileError(DataSet: TDataSet; UpdateKind: TUpdateKind; E: EReconcileError): TReconcileAction;const Acao: array [TUpdateKind] of string = (‘Alterar’,’Inserir’,’Excluir’);var Msg: string; i: Integer;begin if pos(‘PK_CLIENTES’,E.Message)>0 then Msg:=Format(‘Cliente já cadastra-do!’,[]); if pos(‘FK_PRODUTO_TRI’,E.Message)>0 then Msg:=Format(‘Tributação está sendo usada por Produto!’,[]); case UpdateKind of ukDelete: Result := raCancel; ukInsert: Result := raAbort; ukModify: Result := raAbort; end; if Msg=’’ then Msg := ‘Não foi possível completar esta operação, informe a mensagem abaixo ao suporte!’#13+E.Message; ShowMessage(Format(‘Não foi possível %s o registro.’+#13+Msg,[Acao[UpdateKind]])); end;

Page 6: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

dbexpress

06

Listagem 3 - Função CustomReconcileError

Através da mensagem de erro poderemos personalizar a mensagem apre-sentada ao usuário, e para isso teremos que analisar a mensagem retornada pelo banco de dados, por isso, torna-se importante nomear as constraints, primary keys, foreign keys, etc existentes em seu banco de dados, pois dessa forma será fácil efetuar o tratamento via Delphi.

Na listagem 4, demonstro a chamada da função CustomReconcileError dentro do evento OnReconcileError de um ClientDataSet:

procedure TfmCadCanais.cdsCanaisReconcileError( DataSet: TCustomClientDataSet; E: EReconcileError; UpdateKind: TUpdateKind; var Action: TReconcileAction);begin inherited; Action := CustomReconcileError(DataSet, UpdateKind, E);end;

Listagem 4.

O evento OnReconcileError possui quatro parâmetros:

DataSet Indica o ClientDataSet que chamou o método Ap-plyUpdates

E Traz informações a respeito do processo de atualização, tal como a mensagem retornada pelo servidor e várias outras informações

UpdateKind Indica o tipo de operação que está sendo realizada

ukDelete: Excluindo um registro ukInsert: Adicionando novo registro ukModify: Alterando um registro

Action Indica a ação que será adotada quando ocorrer uma falha de atualização, em nossa função iremos utilizar duas de acordo com a operação realizada:

ukDelete: raCancel; ukInsert: raAbort; ukModify: raAbort;

raCancel: Cancela a operação e reverte o registro para seu estado original.

raAbort: Aborta o processo de reconciliação.

Parâmetros do evento OnReconcileError

Garantindo atualizações de múltiplos ClientDataSets

Os tratamentos de erros efetuados através do evento OnReconcileError geralmente atendem a maioria das necessidades neste contexto, contudo, existem situações peculiares onde não conseguimos ga-rantir a integridade dos dados durante o processo de atualização apenas com base neste evento. Por exemplo, supondo que você possua três componentes ClientDataSet sem nenhum tipo de relacionamento entre eles e necessite que todos os três sejam efetivados no banco de dados com sucesso ou todo o processo seja revertido, em resumo: ou grava tudo ou não grava nada! Neste caso teremos que utilizar um controle de transação para garantir a integridade no processo de atualização, todavia vale lembrar que o método ApplyUpdates não levanta nenhuma exceção... assim sendo, como verificar se houve algum erro sem utilizar o evento OnReconcileError? Bem, o método ApplyUpdates é uma função que retorna o número de erros gerados no processo de atualização e dessa forma ficará fácil implementarmos um tratamento coeso dos dados, confira a listagem 5:

procedure SetaTD(var TD: TTransactionDesc);begin Randomize; TD.TransactionID := Trunc(Random(65635)*Now); TD.IsolationLevel := xilREADCOMMITTED;end; Var TD: TTransactionDesc;begin // Configura transação. SetaTD(TD); // Abre transação. SQLConnection.StartTransaction(TD); // Inicia atualização dos ClientDataSets. Try if ClientDataSet1.ApplyUpdates(0) > 0 then raise Exception.Create(‘Erro no 1º ClientDataSet’); if ClientDataSet2.ApplyUpdates(0) > 0 then raise Exception.Create(‘Erro no 2º ClientDataSet’); if ClientDataSet3.ApplyUpdates(0) > 0 then raise Exception.Create(‘Erro no 3º

Page 7: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

dbexpress

07

Sobre o autorAlessandro Ferreira

ClientDataSet’); // Confirma a transação. SQLConnection.Commit(TD); Except

SQLConnection.RollBack(TD); ShowMessage(‘Não foi possível atualizar!’); End;end;

Listagem 5 - Atualização com controle de transação

No caso de ClientDataSets relacionados via Master/Detail não é necessário efetuar este tipo de tratamento, visto que por estarem relacionados será necessário chamar o método ApplyUpdates apenas do ClientDataSet Máster e dessa forma, se você utilizar como parâmetro “0” (ApplyUpdates(0)) o mecanismo Provider/Resolver irá se encarregar de garantir a integridade dos dados.

Conclusão

Demonstrei neste artigo uma abordagem bastante simples e funcional para tratamento de erros na dbExpress/ClientDataSet, onde com duas funções você poderá ter o controle centralizado de erros na atualização de dados em sua aplicação. Forte abraço e sucesso à todos.

Page 8: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

keepalive

08

ou como prevenir o erro 10054/104

Introdução

Nos sistemas com banco de dados Interbase ou Firebird, os quais tem intenção de trabalhar em modo de tempo real ou próximo disso, há um problema com o status do rastreamento das conexões do cliente no lado do servidor, e isso força a desconexão quando no caso do cliente se tornar inaces-sível por causa de uma liberação da conexão. É importante liberar rapidamente os recursos ocupados com estas conexões fantasmas, especialmente quando se usa servidores com estrutura clássica.

Se muitos usuários se conectam ao servidor através de conexões por modem instáveis, o de desconexão se torna extremamente alto.

Por exemplo, um cliente salva um record set alterado, e após o UPDATE ser executado (enquanto o COMMIT ainda não foi) a conexão cai.

Como regra, a aplicação cliente em tais situações se reconectará ao servi-dor, mas o cliente (como ele/ela ainda continua trabalhando com os dados, mesmo após salvar receberá uma mensagem de erro por causa da falha de conexão) não será capaz de salvar as mudanças, uma vez que ele/ela receberá uma mensagem de conflito de travamento (“lock conflict on update”).

A conexão anterior, que abriu a transação (no contexto da qual o UPDATE foi executado, enquanto o COMMIT não foi), ainda guarda os registros.

A falha de conexão talvez ocorra em redes locais também, se o hardware (placas de rede, hubs, comutadores) estão com problemas ou mal conectados, e/ou por causa de interferências na rede.

Nos logs do Firebird e do Interbase, falhas de conexão com o protocolo TCP são mostradas com o erro 10054 no Windows e 104 no Unix, falhas do netbeui são mostradas como erros 108/109.

Métodos de controle de travamento de conexões

No Interbase e no Firebird, os mecanismos de DUMMY-packets ou KEEPAL-IVE-sockets são usados para rastrear e desabilitar tais conexões “mortas”.

No Interbase 5.0 ou mais recente, o mecanismo de DUMMY-packets foi implementado como uma camada da aplicação entre o servidor Firebird/Interbase e o cliente gds/fbclient. Isto está incluído no ibconfig/firebird.conf e não será examinado neste artigo.

Obs: Como sabemos por experiências anteriores, a estabilidade do mecanismo de dummy-packets (o que foi implementado no Interbase 5.0 e corrigido no Firebird 1.5x) depende fortemente dos sistemas operacionais do servidor e do cliente, versão do stack do tcp e muitas outras condições. Pode-se dizer que, a efetividade de tal sistema numa rede real tende a zero.

O KEEPALIVES-packets é um mecanismo mais interessante. Implemen-tado no Interbase 6.0 ou mais recente, tem como propósito rastrear falhas de conexão. O KEEPALIVE é habilitado ajustando a opção SO_KEEPALIVE na abertura.

Não há necessidade de fazer isso manualmente se você está usando o Firebird 1.5x ou mais recente, já que ele foi implementado no código de programação do Firebird Server, para o Classic e Superserver.

Para as versões do Interbase e Firebird mais antigas, há uma variação com a estrutura clássica, assim é necessário um ajuste adicional. Este ajuste é descrito abaixo.

Neste caso, o tcp stack do sistema operacional (ao invés do Firebird Server) se torna responsável pelo status da conexão. No entanto, para habilitar este mecanismo, deve-se ajustar os parâmetros do KEEPALIVE.

Descrição do KEEPALIVE.

O comportamento do KEEPALIVE-sockets é controlado pelo parâmetro presente na tabela seguinte. O tcp stack rastreia o momento que os pacotes param de transmitir entre o cliente e o servidor, executando um timer do KEEPALIVE.

Tão logo o timer chegue no ponto do KEEPALIVE_TIME, o servidor do tcp

Page 9: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

keepalive

09

stack executará a primeira sonda do KEEPALIVE. A sonda é um pacote vazio com um flag ACK que é enviado para o usuário.

Se estiver tudo bem no lado do cliente, então o tcp stack do lado do cliente envia um pacote de resposta com um flag ACK, e o servidor de tcp stack reajusta o timer do KEEPALIVE assim que ele recebe uma resposta.

Se o cliente não responde à sonda, as sondagens do servidor continuam a ser enviadas. A quantidade delas é igual à do valor KEEPALIVE_PROBES, elas são executadas pelo intervalo definido no KEEPALIVE_INTERVAL. Se o cliente não responde à última sonda, então após outro período do KEEPALIVE_INTERVAL expirar, o tcp stack do sistema operacional fecha a conexão, e o servidor (neste caso, uma instância do Firebird ou Interbase) libera todos os recursos ocupados com esta conexão.

Assim, uma conexão do cliente que falhou será fechada após o seguinte período de intervalo: KEEPALIVE_TIME+ (KEEPALIVE_PROBES+1) * KEEPALIVE_INTERVAL.

Por padrão, os valores dos parâmetros são muito grandes, isso os torna ineficazes. Por exemplo, o valor padrão do parâmetro KEEPALIVE_TIME é “2 horas”, tanto em Linux como em Windows.

Certamente, 1 ou 2 minutos seria o suficiente para tomar uma decisão sobre uma desconexão forçada de um cliente inacessível.

Por outro lado, o padrão do KEEPALIVE causa desconexões forçadas em redes Windows, que estão inativas durante estas duas horas.

Abaixo estão os ajustes destes parâmetros para Windows e Linux.

Ajustando o KEEPALIVE no Linux

Os parâmetros do KEEPALIVE no Linux podem ser alterados diretamente por edição dos arquivos de sistema ou chamando o sysctl.

Para o primeiro caso, as seguintes linhas devem ser editadas:

/proc/sys/net/ipv4/tcp_keepalive_time/proc/sys/net/ipv4/tcp_keepalive_intvl/proc/sys/net/ipv4/tcp_keepalive_probes

Para o segundo caso, os seguintes comandos devem ser executados:

sysctl –w net.ipv4.tcp_keepalive_time=valuesysctl –w net.ipv4.tcp_keepalive_intvl=valuesysctl –w net.ipv4.tcp_keepalive_probes=value

O valor está expresso em segundos.

Para o ajuste automático destes parâmetros no caso da reinicialização do servidor, adicione as seguintes linhas ao /etc/sysctl.conf:

net.ipv4.tcp_keepalive_intvl = valuenet.ipv4.tcp_keepalive_time = valuenet.ipv4.tcp_keepalive_probes = value

Substitua <value> pelos valores apropriados.

Se você está usando uma versão anterior do Firebird 1.5x, então deve-se adicionar o seguinte no /etc/xinet.d/firebird:

FLAGS=REUSE KEEPALIVE

Ajustando o KEEPALIVE no Windows 95/98 e MESeção do registro

HKEY_ LOCAL_ MACHINE\System\ CurrentControlSet\Services\VxD\MSTCP

Tudo sobre os ajustes do TCP podem ser encontrados aqui:

http://support.microsoft.com/default.aspx?scid=kb;en-us;158474

Parâmetros:

* KeepAliveTime = milisegundosTipo: DWORDPara Windows 98 tipo STRING.Define o tempo de inatividade da conexão em milisegundos. Quando ele

expira, as sondas do KEEPALIVE começam a ser executadas. O valor padrão é 2 horas (7200000).

* KeepAliveInterval = valor de 32-digitosTipo: DWORDPara Windows 98 tipo STRING.

Define o tempo entre as sondas do KEEPALIVE em milisegundos. Tão logo o intervalo KeepAliveTime expire, após cada período do KeepAliveInterval (em milisegundos), as sondas do KEEPALIVE são enviadas até o número máximo de MaxDataRetries. Se não houver resposta, a conexão se fecha. O valor padrão é 1 segundo (1000).

* MaxDataRetries = valor de 32 dígitosTipo: STRINGDefine o número máximo de sondas do KEEPALIVE. O valor padrão é 5.

Page 10: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

keepalive

10

Ajustando o KEEPALIVE no Windows NT/2000/XP

Seção do registro:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\.

Tudo sobre os ajustes de TCP:

2000/ NT: http://support.microsoft.com/kb/120642XP: http://support.microsoft.com/kb/314053

O p a r â m e t r o M a x D a t a R e t r i e s f o i s u b s t i t u í d o p o r TCPMaxDataRetransmissions.

Todos os outros parâmetros tem o mesmo nome do Windows 9x.

Ajustando o KEEPALIVE nos clientes Windows

Este ajuste é opcional, mas provavelmente reduzirá o número de men-sagens de falhas de conexão se o usuário não tiver um canal de comunicação confiável. Insira nesta seção do registro:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

Parâmetro DisableDHCPMediaSense = 1. Veja uma descrição deste parâmetro aqui:http://support.microsoft.com/?scid=kb%3Bru%3B239924&x=13&y=14

Exemplo

Vamos considerar o ajuste do Firebird 1.5.2 para o sistema operacional Linux.

* Tenha certeza que o mecanismo de DUMMY-packets estão desabilitados no firebird.conf.

...........# DummyPacketsInterval = 0...........

* Tenha certeza que é o arquivo de configuração /etc/sinet.d/firebird

Vamos manter tudo sem mudanças, como está desde a instalação. Nada será adicionado.

* Mudança dos parâmetros do TCP stack

sysctl –w net.ipv4.tcp_keepalive_time = 15sysctl –w net.ipv4.tcp_keepalive_intvl = 10sysctl –w net.ipv4.tcp_keepalive_probes = 5

* Conecte-se à qualquer banco de dados no servidor de qualquer cliente de rede.

* Cheque o tráfego no servidor usando um filtro de pacotes.Se o parâmetro estiver especificado como /proc/sys/net/tcp_keepalive_*,

com 15 segundos após tudo parar no canal, o servidor cria uma sonda.

Se o cliente estiver vivo (“alive”), o servidor recebe um pacote de resposta. 15 segundos após isto, a checagem se repete, e assim por diante.

* Se o cliente está fisicamente desligado (ou se o multiplexador ou o modem são desligados repentinamente – tudo é possível), então o servidor não receberá uma resposta, e o servidor começará a enviar sondas com 10 segundos de intervalo.

Se o cliente não responder à quinta sonda, então 10 segundos após isto, o servidor faz uma descarga, e libera os recursos que estão bloqueando os travamentos.

Se o cliente der algum sinal e responder pelo menos à quinta sonda (se o que está ruim piorar), então, após outros 15 segundos de time-out, o servidor começará a enviar sondas. E assim por diante.

ConclusõesConcluindo, quero dar alguns conselhos sobre como os valores do KEE-

PALIVE devem ser usados.

Primeiramente, determine o valor necessário do KEEPALIVE_TIME. So-mente após este valor é que as sondas do KEEPALIVE serão lançadas.

Se você ver constantemente erros 10054/104 no log do servidor, e você tiver que deletar isto manualmente, é recomendável que você aumente o valor de KEEPALIVE_TIME.

Segundo, os valores de KEEPALIVE_INTERVAL e KEEPALIVE_PROBES de-

Page 11: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

keepalive

11

Sobre o autorAlessandro Ferreira

vem ser suficientes para satisfazer suas necessidades antes de já existirem conexões travadas.

Se os clientes se conectarem ao servidor através de conexões não con-fiáveis, então você deve aumentar o número de sondas o intervalo entre elas, para dar ao usuário uma chance de detectar o problema e se conectar ao servidor.

No caso de clientes que usam conexões de banda larga à Internet, ou acessam o SQL através de uma rede local, é possível diminuir o valor de tempo entre as sondas.

Recomendações gerais:

Se você não tem razões particulares para receber muitas mensagens de erro dos clientes, a respeito dos resultados de gravação, por causa dos conflitos de travamento (não há conexões concorrentes trabalhando com os mesmos dados), então você precisa aumentar a reação do sistema para liberar as conexões travadas.

Praticamente, o valor de KEEPALIVE_TIME deve ser acima ou igual a 1 minuto.

Você mesmo deve determinar qual o maior tempo de uma transação, para que o tráfego não fique sobrecarregado por checagens do KEEPALIVE em conexões de trabalho normais, que lançam grandes transações.

O valor de KEEPALIVE_INTERVAL deve ser maior ou igual a 10 segundos, e o de KEEPALIVE_PROBES igual ou maior que 5.

Quando muitos usuários trabalham simultaneamente, lembre-se que se você ficar checando periodicamente, pode haver um aumento no tráfego de rede.

Lembre-se também que, caso seus usuários mudem os mesmos dados frequentemente, erros de travamento acontecerão como resultado da situa-ção. Neste caso, você precisa tratar este erro na aplicação.

Ao mesmo tempo, a aplicação deve ser capaz de minimizar tais erros.

Exemplos de configuração padrão

Finalmente, aqui estão mais alguns exemplos de configuração.

Downtime é o tempo que os usuários não são capazes de atualizar os

dados (que é o momento da atualização da transação aberta até a conexão travada).

Total time é o tempo de expiração que a conexão travada será fechada.

KEEPALIVE_TIME 1 minutesKEEPALIVE_PROBES 3KEEPALIVE_INTERVAL 30 secondsTOTAL 3 minutes* Clientes que usam conexão de rede; muitas das transações são curtas;

downtime é limitado em 2 minutos

KEEPALIVE_TIME 30 secKEEPALIVE_PROBES 5KEEPALIVE_INTERVAL 10 secTOTAL 90 seconds

* Clientes que usam qualquer conexão; downtime não é definido

KEEPALIVE_TIME 15 minutesKEEPALIVE_PROBES 4KEEPALIVE_INTERVAL 1 minutesTOTAL 20 minutes

* Clientes que usam qualquer conexão, transações contínuas são possíveis no sistema, e o downtime limite é 15 minutos

KEEPALIVE_TIME12 minutesKEEPALIVE_PROBES 7KEEPALIVE_INTERVAL 15 secTOTAL 14 minutes

Espero que estes exemplos que mostrei sejam suficientes para um ajuste correto do TCP stack do mecanismo do KEEPALIVE.

Page 12: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

delphi

12

Acessando o Firebird via Delphi 8 .NET

Firebird

O Firebird é um banco de dados relacional “Open-Source” bastante difundido meio a comunidade de programadores no Brasil e no mundo. O Firebird nasceu com base no Interbase 6 mediante a uma abertura no có-digo fonte deste último proporcinado pelo seu fabricante, ou seja, a própria Borland, que numa estratégia de mercada para difundir o Interbase, abriu seu código fonte e pouco depois, anunciou a versão 6.5 do Interbase, a qual não teria continuidade como “Open-Source”. Mediante isso, uma comunidade liderada por Ann Harrison (considerada a “mãe” do Interbase) foi formada e hoje já temos a versão 1.5 do Firebird e milhares de usuários espalhados pelo mundo.

Uma das preocupações da Borland até o momento, têm sido compati-bilizar seus componentes de acesso a banco de dados, mas especificamente ao Interbase com seu próprio produto, ou seja, atualmente o Interbase comercializado pela Borland está na versão 7.x e o Delphi 8 .NET naturalmente acessa este banco de dados como não poderia ser diferente, utilizando-se de um manage provider específico, o qual infelizmente não é 100% compatível com o Firebird, devido este último ter sofrido diversas implementações e cor-reções de BUGs e dia-a-dia tomando rumos diferentes ao Interbase 7.x.

Isso contudo, não é problema, pois, mesmo antes da concepção do Delphi 8 .NET, um projeto “Open-Source” chamado Firebird .NET Provider Data Provider já estava em andamento, inclusive com uma release final disponível gratuítamente para a comunidade de usuários do Firebird, onde, este surgiu pela necessidade de acesso ao Firebird através de ferramentas para desenvolvimento .NET, como exemplo o Microsoft Visual Studio .NET. Vale ressaltar, que no Delphi 8 .NET a Borland implementou uma camada de acesso chamada BDP (Borland Data Provider) a qual é baseada na tecnolo-gia ADO.NET e oferece ao programador Delphi maior produtividade devido sua integração com os componentes “DB Web”, através dos quais podemos simplesmente ir relacionando componentes da mesma forma que estávamos habituados fazer nas versões anteriores do Delphi.

Bem, neste artigo iremos apresentar estas duas alternativas de conexão e demonstrar como utilizá-las, deixando a você a escolha de qual melhor irá atender suas necessidades.

Criando o Banco de Dados

Antes de demonstrarmos a conexão, necessitamos ter um banco de dados. Assim sendo, abra a ferramenta de administração do Firebird que

esteja habituado a trabalhar, crie um novo banco, como sugestão nomeie “CADFB15.FDB”. A seguir, crie uma tabela chamada CLIENTES, a qual irá conter a estrutura apresentada na listagem 1.

CREATE TABLE CLIENTES ( ID INTEGER NOT NULL, NOME VARCHAR (80), ENDERECO VARCHAR (80), BAIRRO VARCHAR (30), CIDADE VARCHAR (30), UF CHAR (2), CEP CHAR (10), DOC1 VARCHAR (18), DOC2 VARCHAR (18), TELEFONE VARCHAR (14));/* Chave Primária */ALTER TABLE CLIENTES ADD CONSTRAINT PK_CLIENTES PRIMARY KEY (ID);

Listagem 1 – Criando a tabela

Para o campo ID vamos criar um generator e uma trigger para que o mesmo seja incrementado automaticamente, veja a listagem 2.

/* Generator */CREATE GENERATOR GEN_CLIENTES_ID ; /* Trigger */CREATE TRIGGER TRG_CLIENTES_BI0 FOR CLIENTES ACTIVEBEFORE INSERT POSITION 0ASbegin NEW.ID = GEN_ID(GEN_CLIENTES_ID, 1);end

Listagem 2 – Generator e Trigger

Page 13: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

delphi

13

Agora vamos ao que realmente interessa, a conexão via BDP!

Acessando o Firebird via BDP

Junto ao Delphi 8 .NET a Borland disponibilizou drivers BDP para acesso a vários bancos de dados, sendo: DB2, Interbase, MSAccess, MSSQL e Oracle. Bem, você pode estar pensando, posso acessar o Firebird utilizando o driver para Interbase assim como estou habituado a fazer no dbExpress, onde existe compatibilidade entre ambos, certo? Errado! Devido a várias implementações e correções efetuadas no Firebird esta compatibilidade não é 100% e o driver que acompanha o Delphi 8 .NET até consegue efetuar a conexão a um banco Firebird, contudo não consegue extrair informações de tabelas, índices, etc. Mediante isso, o mesmo autor do projeto Firebird .NET Provider Data Provider, iniciou a implementação de um driver BDP específico para o Firebird. Até o momento da conclusão deste artigo, a versão disponível é a versão Alpha 1 para o .NET Framework 1.1. Apesar de ser uma versão Alpha, executamos vários testes e os resultados forem surpreendentes, acredito que em breve teremos uma versão final. Bem, o primeiro passo é efetuar o download do “BDP For Firebird” no seguinte endereço:

http://www.ibphoenix.com/main.nfs?a=ibphoenix&s=1089111581:165&page=ibp_download_dotnet

A instalação é bastante simples, basta ir clicando em “Próximo” até o final. Bem, este é o primeiro passo da instalação. Antes de abrir o Delphi 8 .NET, iremos necessitar efetuar entradas nos arquivos BdpDataSources.xml e BdpConnections.xml, ambos disponibilizados na pasta ...\Borland\BDS\2.0\Bin. Abra estes arquivos através do bloco de notas por exemplo, e adicione as seguintes entradas ao final dos mesmos:

* BdpDataSources.xml:

<provider name=”Firebird” connectionStringType=”FirebirdSql.Data.Bdp. FbConnectionString, FirebirdSql.Data.Bdp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c7d0a028dd9e545b”> <objectTypes> <objectType>Tables</objectType> <objectType>Procedures</objectType> <objectType>Views</objectType> </objectTypes></provider>

* BdpConnections.xml:

<BdpConnectionString xsi:type=”FbConnectionString”> <Name>FbConn1</Name> <Database>localhost/3050:employee.fdb</Database> <UserName>sysdba</UserName> <Password>masterkey </Password> <Assembly>FirebirdSql.Data.Bdp,Version=1.0.0.0,

Culture=neutral,PublicKeyToken=c7d0a028dd9e545b</Assembly></BdpConnectionString>

Prosseguindo, acesse o “Data Explorer” e observe que agora temos um ítem “Firebird” o qual representa nossa “ponte” ao Firebird, veja a figura 1.

Figura 1 – Data Explorer

Para testar, vamos criar um nova aplicação ASP.NET e para isso, acesse o menu File | New | Asp.Net Web Application, de um nome que achar mais conveniente ou simplesmente clique em OK para confirmar a sugestão do Delphi. Estando no “Data Explorer”, clique da direito sobre “Firebird” e selecione “Add New Connection”, com isso será apresentada uma tela igual a figura 2.

Page 14: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

delphi

14

Figura 2 – Adicionando nova conexão

Informe um nome para a conexão e clique OK. Feito isso, será adi-ciona a nova conexão, clique da direita sobre a mesma e selecione “Modify Connection”, com isso será apresentado o “Connections Editor”, conforme demonstra a figura 3.

Figura 3 – Connections Editor.

Como pode observar, não temos nada de estranho aqui e sim muito pelo contrário. No “Connections Editor” iremos informar o path do banco de dados, usuário, senha, ou seja, tudo que é necessário para a conexão com nosso banco de dados. Após configurar os parâmetros, clique no botão “Test”

para certificar-se de que tudo está OK e caso positivo, clique em OK. Voltando ao “Data Explorer”, expanda nossa conexão clicando no (+) e poderá observar os ítens: Tables, Views e Procedures. Expanda o ítem Tables clicando no (+) irá visualizar a tabela CLIENTES. Clique sobre a tabela e arraste a mesma sobre seu WebForm. Com isso, automaticamente serão adicionados um componente BdpConnection e um BdpDataAdapter, nomeie como cnxClientes e adpClientes, respectivamente. Feito isso, vamos efetuar as configurações necessárias no adpClientes e gerar um objeto DataSet... Clique da direita sobre o adpClientes e selecione “Configure Data Adapter”, veja a figura 4.

Figura 4 – Configuração do Data Adapter.

Vá até a aba “DataSet”, clique na opção “New DataSet” e digite “dsClientes” e para finalizar clique OK, com isso será adicionado automatica-mente um componente DataSet e para concluir a configurações dos compo-nentes responsáveis ao acesso e manutenção no banco de dados, adicione um componente DBWebDataSource, disponibilizado na “Tool Palette” no grupo “DB Web”, nomeio como srcClientes e configure sua propriedade DataSource para dsClientes (que é o nosso componente DataSet gerado via adpClientes). Agora, vá ao evento OnApplyChangesRequest do srcClientes e adicione a seguinte instrução apresentada na listagem 3.

procedure TWebForm_CadCli.srcClientes_OnApplyChangesRequest(sender: System.Object; e: Borland.Data.Web.WebControlEven-tArgs);begin adpClientes.AutoUpdate;end;

Listagem 3 – Código no evento OnApplyChangesRequest.

Até aqui, implementamos o “motor” de nosso simples cadastro, o qual irá permitir adicionar, alterar, excluir, enfim, fazer toda a manutenção necessária em nossa tabela CLIENTES. Vamos agora implementar a interface

Page 15: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

delphi

15

onde o usuário irá interagir com nosso aplicativo. Comece por adicionar um componente DBWebNavigator disponibilizado na “Tool Palette” no grupo “DB Web” o qual iremos nomear navClientes, configure a propriedade ButtonType para ButtonIcons, a propriedade DBDataSource para srcClientes e a proprie-dade TableName igual a CLIENTES. Após isso, adicione componentes “Label” (disponibilizado na “Tool Palette” no grupo “Web Controls”) e componentes “DBWebTextBox” (disponibilizado na “Tool Palette” no grupo “DB Web”), feito isso, iremos fazer a ligação destes DBWebTextBox com as colunas da tabela CLIENTES onde para isso iremos configurar a propriedade DBDataSource para srcClientes e a propriedade TableName igual a CLIENTES e a propriedade ColumnName para cada coluna da tabela. Na figura 5 apresentamos uma sugestão para o layout.

Figura 5 – Layout sugerido

Se todas as ligações estiverem corretas, nosso exemplo estará pronto e o próximo passo é só efetuar o teste, para isso, acesse o menu “Run” e escolha “Run Without Debugging”, poderia simplesmente teclar <F9>, contudo, a execução “sem debug” é bem mais leve, use <F9> somente quando necessitar utilizar o debug. A figura 6 demonstra nosso aplicativo em execução.

Figura 6 – Exemplo em execução

Conclusão

Até esta parte demonstramos como efetuar a conexão com o Firebird utilizando a tecnologia BDP graças ao driver disponibilizado pelo Carlos Guzmán Álvarez, autor e mantene-dor do Borland Data Provider For Firebird, bem como do Firebird .NET Provider, o qual iremos abordar daqui por diante, contudo, gostaria de ressaltar que trabalhar com BDP é muito mais simples e produtivo que os demais manage providers existentes para a plataforma .NET.

Download

O pro jeto de exemplo apresentado neste ar-t i g o e s t á d i s p o n í v e l p a r a d o w n l o a d e m http://files.theclub.com.br/download/FB_CadAspNet.zip

Firebird .NET Data Provider

O Firebird .NET Data Provider é um driver escrito especificamente para acesso ao Firebird dentro da plataforma .NET, podendo ser utilizado no Del-phi 8.NET, no Microsoft Visual Studio .NET, no C#Builder, etc. Assim como o Borland Data Provider For Firebird, o Firebird .NET Data Provider também foi desenvolvido e é mantido pelo Carlos Guzmán Álvarez, em regime “Open-Source”, seu código fonte foi escrito em C# e está totalmente disponível.

Neste artigo, iremos demonstrar sua utilização dentro do Delphi 8 .NET e o primeiro passo é efetuar o download do Firebird .NET Data Provider, o qual está disponível no endereço:

http://www.ibphoenix.com/main.nfs?a=ibphoenix&s=1083754380:150868&page=ibp_download_dotnet

O release oficial corresponde a versão 1.6, lembrando que deveremos efetuar o download para a versão .NET Framework 1.1, visto ser esta a versão do framework que você tem instalado em sua máquina.

Após efetuar o download, a instalação segue o clássico padrão “Next... Next... Finish”, sem segredo algum! Agora, abra o Delphi 8 .NET, vá ao menu Component | Installed .NET Components | .NET Components e irá ter acesso a um formulário semelhante a figura 7.

Figura 7 – Componentes .NET

Page 16: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

delphi

16

Antes de mais nada, digite na caixa de edição “Category” o nome do grupo onde componentes serão disponibilizados, como exemplo “Firebird.NET”. Seguindo, clique em “Select an Assembly...” e vá até a pasta onde o Firebird .NET Data Provider foi disponibilizado e se você manteve o caminho padrão, estará em <Arquivos de Programas>\FirebirdNETProvider1.6 e selecione o as-sembly FirebirdSql.Data.Firebird.dll, o qual contém os componentes à serem instalados no Delphi 8 .NET e clique em OK para finalizar.

Após a instalação, poderá encontrar os novos componentes no Tool Palette, conforme demonstra a figura 8.

Figura 8 – Firebird .NET Data Provider

Uma geral pelos componentes

A seguir, iremos apresentar os quatro componentes através dos quais ire-mos fazer todos os processos necessário para conexão, seleção e manutenção de dados em bancos Firebird.

FbConnection

O FbConnection, como o próprio nome sugere é o componente respon-sável e prover a conexão com o banco de dados, ou seja, neste iremos informar a string de conexão com o banco de dados, o nome do usuário, a senha e demais configurações necessárias... Este componente possui um editor de propriedades através do qual poderá configurar a conexão com o banco de dados, veja a figura 9.

Figura 9 – Configurações da conexão com um banco Firebird

Vamos descrever alguns dos principais métodos disponíveis no compo-nente FbConnection, acompanha a figura 10.

FbConnection

BeginTransaction Responsável pelo controle de transações, sendo so-brecarregado permitindo combinar parametrizações diferentes, seu retorno é um objeto tipo FbTransac-tion, através do qual poderemos efetuar Commit, RollBack, etc...

CreateCommand Prover a implementação de instruções SQL retor-nando um objeto tipo FbCommand, através do qual iremos fazer a execução dos referidos comandos.

Create Construtor, pode receber a string de conexão como parâmetro

ConnectionString Recebe a string de conexão para acesso ao banco de dados

Close Fechar a conexão corrente

Open Abrir a conexão Figura 10 – alguns métodos do FbConnection

FbDataAdapter

Este componente, fazendo uma comparação bem simplória, seria equivalente aos componentes DataSetProvider+SQLDataSet. É através deste componente que podemos efetuar a atualização e seleção de dados. Vamos analisar as principais propriedades e métodos deste componente.

FbDataAdapter

SelectCommand Propriedade do tipo FbCommand responsável em armazenar a instrução “Select” à ser executada.

Page 17: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

delphi

17

DeleteCommand Propriedade do tipo FbCommand responsável em armazenar a instrução de “Delete” à ser executada.

InsertCommand Construtor, pode receber a string de conexão como parâmetro

UpdateCommand Propriedade do tipo FbCommand responsável em armazenar a instrução de “Update” à ser executada.

Fill Método responsável em “descarregar” os dados retornados por um “Select”. Este método é sobre-carregado podendo receber como parâmetros: Data-Set, DataTable, StartRecord, MaxRecords, havendo combinação entre os referidos parâmetros

Update Método responsável em aplicar as atualizações arma-zenadas em um componente DataSet. Este método é sobre-carregado podendo receber parâmetros: DataSet, TableName e DataRow

Figura 11 – alguns métodos do FbDataAdapter

FbCommand

Podemos fazer uma analogia deste componente a uma Query unidirecio-nal existente no Delphi (Win32). Através dele podemos executar instruções Insert, Update, Delete e Select de forma bem simples e prática. Conforme mencionamos anteriormente na descrição do componente FbDataAdapter, as propriedades SelectCommand, DeleteCommand, InsertCommand e UpdateCommand são do tipo FbCommand e dessa forma, todas as proprie-dades e métodos apresentados poderão ser aplicados no FbDataAdapter. Vamos analisar as principais propriedades e métodos do FbCommand.

FbCommand

Cancel Tenta cancelar a execução de uma instrução

CommandPlan Verifica o plan que o servidor utilizou

CommandText Recebe a instrução à ser executada pelo FbCommand

CommandTimeOut Setar ou verificar a configuração de tempo ocioso

CommandType Definir como o FbCommand irá se comportar, po-dendo ser: TableDirect, StoredProcedure ou Text

Connection Associar a um componente FbConnection

ExecuteNonQuery Executa a query e retorna o número de registros afetados

ExecuteReader Executa a query e retorna um conjunto de dados utilizando para isso um objeto FbDataReader.

ExecuteScalar Executa a query e retorna a primeira coluna da primeira linha resultante da query.

Parameters Adicionar e atribuir valores quando utilizamos commandtext parametrizado, tem como principal método Add.

Prepare Método chamado internamente pelos métodos ExecuteNonQuery, ExecuteReader e ExecuteScalar.

Transaction Recebe um objeto FbTransaction para efetuar con-troles de transação

Figura 12 – alguns métodos do FbCommand

FbCommandBuilder

Este componente tem por finalidade ajustar as instruções SQL existentes no componente FbDataAdapter quando efetuamos a chamada do método Update passando um DataSet como parâmetro. Em uma analogia com o Delphi (Win32), este componente faria a mesma função do evento OnGetTableName e a propriedade UpdateMode do componente DataSetProvider.

Na prática...

Bom, até agora apenas descrevemos os componentes que integram o Firebird .NET Data Provider. Vamos agora construir um simples projeto de exemplo a fim de melhor entendermos seu funcionamento. Primeiramente, vamos criar um banco de dados, sugiro o nome ACESSANDOFIREBIRD.FDB. Na listagem 1 segue o script da tabela.

/* Table: GRUPOS */

CREATE TABLE GRUPOS (

ID INTEGER NOT NULL,

NOME VARCHAR (30));

/* Primary keys definition */

ALTER TABLE GRUPOS ADD CONSTRAINT PK_GRUPOS PRIMARY KEY (ID);

Listagem 1 – Script da tabela

Estando com o banco e a tabela prontos, abra o Delphi 8 .NET e vamos criar um nova aplicação ASP.NET e para isso, acesse o menu File | New | Asp.Net Web Application, de um nome que achar mais conveniente ou simples-mente clique em OK para confirmar a sugestão do Delphi. Vá ao Tool Palette | Firebird .NET e adicione um componente FbConnection. Feito isso, acesse a propriedade ConnectionString e faça a configuração através Connection String Editor, como mostra a figura 13.

Page 18: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

delphi

18

Figura 13 – Configurando a conexão

Clique em “Accept” para concluir a configuração da conexão. Continuando, adicione um componente FbDataAdapter e ajuste sua proprie-dade Name para adpGrupos e para finalizar adicione um componente DataSet (grupo Data Components).

Antes de iniciarmos a codificação, vamos implementar a interface através da qual faremos a entrada e manutenção nos dados. Para isso, adicione os seguintes componentes: dois Labels (grupo Web Controls) e ajuste a pro-priedade Text para “Código” e “Nome”; dois TextBoxs (grupo Web Controls) e ajuste a propriedade Name para “txtCodigo” e “txtNome”; seis Buttons (grupo Web Controls) e ajuste a propriedade Name para “btnNovo”, “btn-Gravar”, “btnCancelar”, “btnExcluir”, “btnAnterior”, “btnProximo”; E para finalizarmos, adicione um componente DataGrid ajustando sua propriedade DataSource para DataSet1.

Figura 14 – layout sugerido

Vamos partir agora para a codificação a fim de fazer nosso simples ca-dastro funcionar. Acesse a unit e abaixo da sessão implemetation adicione o código apresentado na listagem 2.

{ Mandar Foco para componente }

procedure SetFocus(aPage: Page; Ctrl: System.Web.UI.Control);

begin

with aPage do

RegisterStartupScript(‘focus’,

System.String.Format(‘<SCRIPT>document.getElementById(“{0}”).focus();</SCRIPT>’, [Ctrl.ID]));

end;

{ Mostra Mensagens }

procedure Alert(aPage: Page; Texto: String);

begin

with aPage do

RegisterStartupScript(‘ClientScript’,

System.String.Format(‘<script>alert(“{0}”);</script>’, [Texto]));

end;

Listagem 2 –Procedures para Foco e Mensagem

A procedure SetFocus serve para mandar o foco para um componente existente no webform e a procedure Alert serve para mostrar uma caixa de mensagem. Continuando, vamos implementar o método que será respon-sável em atualizar/mostrar os dados na tela, efetuando o select na tabela e descarregando os dados em nosso objeto DataSet, veja a listagem 3. (tecle CRTL+SHIFT+C para efetuar a declaração do método dentro da classe do webform).

{ Atualizar a visualização }

procedure TWebForm1.BindData;

Page 19: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

delphi

19

begin

{ Select }

adpGrupos.SelectCommand := FbCommand.Create;

adpGrupos.SelectCommand.Connection := FbConnection1;

adpGrupos.SelectCommand.CommandText := ‘Select * From GRUPOS’;

{ Mostra os dados }

FbConnection1.Open;

try

adpGrupos.Fill(DataSet1, ‘GRUPOS’);

Session.Add(‘dsGrupos’, DataSet1);

DataGrid1.DataBind;

finally

FbConnection1.Close;

Session.Add(‘Operacao’, ‘Browse’);

end;

end;

Listagem 3 – Método para atualizar/mostrar dados na tela

Observe que método BindData que instânciamos um objeto tipo FbCommand para a propriedade SelectCommand do adpGrupos, pois, con-forme mencionamos anteriormente esta propriedade é do tipo FbCommand. Depois de instânciada, atribuímos o objeto de conexão (FbConnection) e a instrução select. Antes de executarmos é necessário abrir a conexão, pois isso não é feito automaticamente pelo adoGrupos. O método Fill é “quem” executa o select e descarrega os dados em nosso DataSet1 e para que nosso DataGrid apresente os dados do DataSet a ele associado, chamamos o método DataBind. E para finalizar, fechamos a conexão e adicionamos uma string na sessão para indicar a operação atual que estamos executando.

Os componente TextBox não estão fazendo nenhuma referência ao DataSet1que contém os dados, e dessa forma nós teremos que estar ali-

mentando-os a fim de que os dados sejam visualizados, assim sendo, vamos implementar um método que irá buscar dados no DataSet1 e atribuir aos TextBox, confira a listagem 4. (tecle CRTL+SHIFT+C para efetuar a declaração do método dentro da classe do webform).

{ Copiar os dados do DataSet para os TextBox }

procedure TWebForm1.Copia(Index: Integer);

begin

txtCodigo.Text := dsGrupos.Tables[‘GRUPOS’].Rows[Index][‘ID’]. ToString;

txtNome.Text := dsGrupos.Tables[‘GRUPOS’].Rows[Index][‘NOME’].ToString;

end;

Listagem 4 – Método para atualizar os TextBox.

O método Copia recebe como parâmetro o índice da linha existente na DataTable dentro do DataSet.

Bem, agora que estamos com os métodos auxiliares implementados, vamos continuar a codificação dos botões e da página. Localize na unit o evento Page_Load. Este evento ocorre toda vez que a página é atualizada e também a primeira vez que a mesma é carregada e na primeira vez que ela for carregada vamos atualizar a visualização dos dados em tela, configura a listagem 5.

{ Inicializar }

procedure TWebForm1.Page_Load(sender: System.Object; e: System.EventArgs);

begin

if not (IsPostBack) then

begin

BindData;

DataGrid1.SelectedIndex := 0;

Page 20: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

delphi

20

if dsGrupos.Tables[‘GRUPOS’].Rows.Count > 0 then

Copia(0);

end;

end;

Listagem 5 – Page_Load

A função IsPostBack retorna falso na primeira execução deste evento, ou seja, indica que é a primeira vez que a página está sendo carregada, da segunda execução em diante, a função IsPostBack retorna verdadeiro.

Partiremos agora para a codificação dos botões. Acesse o webForm (F12), dê um duplo clique sobre o “btnNovo” e adicione o código apresentado na listagem 6.

{ Adicionar novo registro }procedure TWebForm1.btnNovo_Click(sender: System.Object; e: System.EventArgs);

begin DataGrid1.SelectedIndex := -1;

Session.Add(‘Operacao’, ‘Insert’);

txtCodigo.Text := ‘’;

txtNome.Text := ‘’;

SetFocus(Page, txtCodigo);

end;

Listagem 6 – Evento OnClick do btnNovo.

Acompanhando o código sugerido para o evento OnClick do “btnNovo”, primeiro desfazemos a seleção de linha no DataGrid, informamos na sessão que a operação atual será um novo registro, limpamos o texto dos TextBox e mandamos o foco para o “txtCodigo”.

O próximo passa é a codificação do “btnGravar”, apresentamos o código completo para o evento OnClick desta botão na listagem 7.

{ Gravar novo registro e alteração de registro }

procedure TWebForm1.btnGravar_Click(sender: System.Object; e: System.EventArgs);

begin

if Session[‘Operacao’].ToString = ‘Insert’ then

begin

FbConnection1.Open;

try

{ Insert }

with adpGrupos do

begin

InsertCommand := FbConnection1.CreateCommand;

InsertCommand.CommandText :=

‘INSERT INTO GRUPOS(ID, NOME) VALUES (@ID, @NOME)’;

InsertCommand.Parameters.Add(‘@ID’, FbDbType.Integer).Value := txtCodigo.Text;

InsertCommand.Parameters.Add(‘@NOME’, FbDbType.VarChar).Value := txtNome.Text;

InsertCommand.ExecuteNonQuery;

Alert(Page, ‘Registro incluído com sucesso!’);

end;

finally

FbConnection1.Close;

end;

end

Page 21: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

delphi

21

else

begin

FbConnection1.Open;

try

{ Update }

with adpGrupos do

begin

UpdateCommand := FbConnection1.CreateCommand;

UpdateCommand.CommandText := ‘UPDATE GRUPOS SET NOME = @NOME WHERE ID = @ID’;

UpdateCommand.Parameters.Add(‘@ID’, FbDbType.Integer).Value := txtCodigo.Text;

UpdateCommand.Parameters.Add(‘@

NOME’, FbDbType.VarChar).Value := txtNome.Text;

UpdateCommand.ExecuteNonQuery;

Alert(Page, ‘Registro alterado com sucesso!’);

end;

finally

FbConnection1.Close;

end;

end;

Session.Add(‘Operacao’, ‘Browse’);

BindData;

end;

Listagem 7 – Evento OnClick do btnGravar.

Analisando o código do evento OnClick do “btnGravar”, primeiro verifi-camos qual a operação que está sendo realizada no momento, caso seja a in-clusão de um novo registro, abrimos a conexão (FbConnection), instânciamos a propriedade InsertCommand (tipo FbCommand) do adpGrupos, atribuímos a conexão, adicionamos a instrução de Insert parametrizado, passamos os componentes TextBox como parâmetro ao InsertCommand, e executamos através do método ExecuteNonQuery.

Porém, caso a operação registrada na sessão não seja um “Insert”, iremos fazer apenas a alteração do registro. Veja que a lógica basicamente é a mesma, instânciamos a propriedade UpdateCommand, adicionamos a instrução de Update também parametrizada. Ao final do evento, atualizamos a sessão e chamamos o método BindData para a atualização da visualização em tela.

O código no evento OnClick do “btnCancelar é bastante simples, apenas atualizamos a sessão e o ponteiro no DataGrid, confira na listagem 8.

{ Cancelar Edição }

procedure TWebForm1.btnCancelar_Click(sender: System.Object; e: System.EventArgs);

begin

Session.Add(‘Operacao’, ‘Browse’);

Copia(DataGrid1.SelectedIndex);

end;

Listagem 8 – OnClick do btnCancelar

Continuando, vamos para a codificação do “btnExcluir” no qual também não teremos novidades... Veja a listagem 9.

{ Excluir registro selecionado }

procedure TWebForm1.btnExcluir_Click(sender: System.Object; e: System.EventArgs);

begin

FbConnection1.Open;

try

Page 22: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

delphi

22

{ Delete } with adpGrupos do begin DeleteCommand := FbConnection1.CreateCommand; DeleteCommand.CommandText := ‘DELETE FROM GRUPOS WHERE ID = @ID’; DeleteCommand.Parameters.Add(‘@ID’, FbDbType.Integer).Value := txtCodigo.Text; DeleteCommand.ExecuteNonQuery; Alert(Page, ‘Registro excluído com sucesso!’); end; finally FbConnection1.Close; BindData; end;end;

Listagem 9 – OnClick do btnExcluir

E para finalizamos vamos implementar o códigos do botões “bt-nAnterior” e “btnProximo” os quais nos permitirão navegar entre os registros, acompanha o código na listagem 10.

{ Ir para o próximo registro }procedure TWebForm1.btnProximo_Click(sender: System.Object; e: System.EventArgs);begin if DataGrid1.SelectedIndex < dsGrupos.Tables[‘GRUPOS’].Rows.Count-1 then begin DataGrid1.SelectedIndex := DataGrid1.SelectedIndex+1; Copia(DataGrid1.SelectedIndex); end; end;{ Ir para o registro anterior }procedure TWebForm1.btnAnterior_Click(sender: System.Object; e: System.EventArgs);begin if DataGrid1.SelectedIndex > 0 then begin DataGrid1.SelectedIndex := DataGrid1.SelectedIndex-1; Copia(DataGrid1.SelectedIndex); end;end;

Listagem 10 – OnClick do btnAnterior e btnProximo

A codificação dos botões “btnProximo” e “btnAnterior” é bastante simples. Nela utilizamos a propriedade SelectedIndex do DataGrid a fim de movimentar a seleção de registros no DataGrid e também através do método Copia atualizar a visualização nos TextBox.

Com isso, finalizamos a implementação de nosso cadastro utilizando o Firebird .NET Data Provider, execute a aplicação e se tudo correr bem você terá um resultado parecido com a figura 9.

Figura 9 – Cadastro em execução

Conclusão

Acessar o Firebird dentro da plataforma .NET ficou muito simples utilizando os manage providers disponibilizados pelo Carlos Guzmán Álvarez, o qual têm dado uma grande colaboração para a comunidade Firebird. O Fire-bird .NET Data Provider pode ser utilizado praticamente em qualquer estúdio de desenvolvimento .NET, pois foi implementado dentro das especificações exigidas para isso. É inegável que o acesso a banco de dados provido via BDP é muito mais simples, contudo isso é uma particularidade implementada no Delphi 8 .NET e é sempre importante termos outras alternativas no mercado, permitindo a nós programadores adotarmos aquela que melhor irá atender as nossas necessidades.

Download

O projeto de exemplo apresentado neste artigo está disponível para download em

http://files.theclub.com.br/download/AcessandoFirebird.zip

Page 23: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

dicas & truques

23

Page 24: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

Controlador de versoes

24

Pasta de trabalho – (Working Folder)

A forma mais comum de se utilizar o controlador de versões é manter uma versão local onde são feitas as alterações e depois submetidas à base centralizada.

Working folder (pasta de trabalho) é a definição dada para um diretório na máquina local dos integrantes da equipe onde são baixados todos os arquivos para consulta e edição.

Cada pessoa tem sua forma de organizar os arquivos no computador, porém, recomendamos que seja definido um padrão de diretório para todos os integrantes da equipe, pois existem arquivos que referenciam outros dentro do mesmo projeto, e se a pasta de trabalho não for padronizada, es-sas referências ficarão quebradas. Definiremos que o diretório padrão para a pasta de trabalho, será: C:\VSSBase.

Para definir a pasta de trabalho no Microsoft Source Safe, clique com o botão direito sobre a raiz dos projetos e selecione: “Set Working Folder...”

Utilizando o Controlador de Versões

Digite o caminho “C:\VSSBase” e clique em ok.

Pronto, agora todos os projetos partindo dessa estrutura serão manipu-lados no diretório “C:\VSSBase”. Você poderá definir outra pasta de trabalho para projetos específicos, caso não queira que tudo seja manipulado no mesmo diretório, inclusive poderá definir uma pasta compartilhada pela rede de um outro computador ou servidor de arquivos.

Criando projetos

O que entendemos como diretórios o Microsoft Source Safe trata como projetos.

Para criar um novo projeto, selecione a pasta (projeto) que conterá o novo projeto, clique com o botão direito e selecione “Create Project...”.

Quando se está desenvolvendo em equipe (2 ou mais pessoas), o controle de versões dos artefatos do projeto como por exemplo documentação e código fonte, fica inviável de ser feito manualmente. Para ilustrar bem a questão, confesso que tive problemas com meu penúltimo livro quando recebi os retornos dos revisores. Em meu último livro, intitulado Visual Studio Team System Rocks, não vacilei e trabalhei com uma ferramenta de controle de versão.

Adotando uma ferramenta para gerenciar essa tarefa, ganhamos produtividade e, com disciplina, eliminamos problemas de retrabalho com perda de arquivos e versões inconsistentes.

Page 25: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

controlador de versoes

25

Digite o nome do projeto que você está criando, obedecendo as mesmas

regras de criação de diretórios do sistema operacional. Caso deseje, coloque na caixa”Comment” um comentário sobre o projeto

Adicionando arquivos a projetos

Para adicionar arquivos aos projetos, selecione o projeto e clique em File/Add Files...

Se preferir utilize a opção na barra de ferramentas:

Localize o(s) arquivo(s) na janela auxiliar e clique em “Add”

Novamente você poderá adicionar comentários para os arquivos adi-cionados caso deseje.

Page 26: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

controlador de versoes

26

Conceito Check-In / Check-Out – Editando Arquivos

Para alterar um arquivo, você sempre precisará reservá-lo com check-out, depois de fazer as alterações, utilizar check-in, para subir a nova versão para o database.

Esse processo funciona como um semáforo, e impede que um arquivo seja alterado por duas pessoas, a não ser que o database esteja configurado para aceitar múltiplos check-outs.

Para reservar um arquivo para edição, selecione o arquivo, clique com o botão direito e escolha “Check-out”, você poderá cadastrar um comentário para a alteração que irá fazer.

O arquivo ficará com um ícone vermelho indicando o estado de check-out:

Agora você pode abrir o arquivo e realizar as alterações necessárias.

Para subir a nova versão do arquivo, realizamos o processo de check-in, depois de salvar o arquivo, selecione-o, clique com o botão direito e escolha “Check-in”, a janela de comentários será exibida novamente para que você cadastre o comentário final e a nova versão do arquivo será armazenada no database.

Multiple Check-Out / Merge Check-In

O Visual Source Safe também oferece o suporte para a configuração de ambientes onde um mesmo arquivo pode ser alterado simultaneamente por dois ou mais usuários, essa é uma configuração interessante para ambientes onde existem fontes que precisem constantemente serem alterados por um mesmo desenvolvedor. Para isso é necessário habilitar isso na interface de administração do repositório do Visual Source Safe dentro das opções do Database (Veja figura abaixo) a opção “Allow multiple checkouts”.

Trabalhando em um ambiente com múltiplos check-outs.

Quando estamos trabalhando em ambiente com múltiplos check-outs, se faz necessário a demonstração da situação de uso onde um arquivo é alterado simultaneamente por mais de um usuário.

Bom o primeiro impacto que podemos verificar é que o ícone de um arquivo com check-out em ambientes de múltiplos check-outs é um pouco diferente, veja abaixo:

Page 27: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

controlador de versoes

27

Abaixo ilustramos passo a passo um cenário de alterações simultâneas. Imagine que o arquivo teste.cs será alterado simultaneamente pelo

Usuário A e pelo Usuário B.1. Usuário A faz o check-out do arquivo para edição e implementa

algumas modificações conforme a figura abaixo:

Arquivo Original Arquivo Editado pelo Usuário A

2. Usuário B faz o check-out do arquivo para edição;Nesse momento o Visual Source Safe irá alertar o Usuário B que já existe

um usuário com esse arquivo em check-out:

O Usuário B deverá clicar em “Yes” para continuar com a ação de check-out.

Abaixo as alterações que o usuário irá realizar no mesmo arquivo:

Arquivo Original Arquivo Editado pelo Usuário B

3. O Usuário A salva o arquivo e faz o check-in das suas alterações;4. O Usuário B salva o arquivo e faz o check-in das suas alterações;Nesse momento o Visual Source Safe reconhece que houveram mais de

um check-in do mesmo arquivo e pede a permissão ao último usuário para que seja feito um “merge” das duas versões ajustando os conflitos;

5. O Visual Source Safe “entende” as alterações feitas pelo dois usuários e faz o merge dos arquivos, veja como ficou o arquivo:

E se os dois usuários alterarem a mesma linha de código ?

Em um ambiente que permite múltiplos check-outs, podem acontecer situações em que dois usuários tentam alterar a mesma linha do código fonte simultaneamente, nesses casos o último usuário a realizar o check-in terá que tomar a decisão de como será a real versão do fonte.

O Visual Source Save exibe automaticamente uma janela igual a janela a baixo para que seja feito a decisão final de como deve ficar o arquivo:

Page 28: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

controlador de versoes

28

Depois que o arquivo estiver corretamente acertado no frame “Merged Version” (parte inferior), é só clicar em “Save” e fechar a janela, que o check-in será realizado com aquela versão.

Baixando a ultima versão de um projeto

Para manter sua pasta de trabalho atualizada, ao iniciar a alteração dos insumos do projeto, selecione o projeto e baixe as últimas versões dos arquivos, para isso, basta selecionar o projeto, clicar com o botão direito e escolher “Get Latest Version...”

O Source Safe exibirá a janela “Get”, para você selecionar o local onde deseja baixar os arquivos, se você não alterar o local ele assume a estrutura hierárquica idêntica partindo do “C:\VSSBase”. Para baixar projetos e sub-pro-jetos, selecione as opções “Recursive” e “Build tree (override working folders)”, dessa forma você terá a última versão de todos os insumos do projeto.

Recuperando o Histórico de versões – (Show History...)

A maior vantagem da utilização do controlador de versão é a possibilidade de voltarmos facilmente para uma versão mais antiga de um determinado arquivo ou projeto.

Para visualizar o histórico de versões de projetos ou arquivos, selecione o arquivo ou projeto e escolha “Show History...”:

O Source Safe exibirá uma janela com todas as versões do arquivo ou

projeto selecionado.

Nessa janela você poderá visualizar (View), recuperar (Get), voltar a versão

(RollBack) e comparar duas versões de um mesmo arquivo (Diff). Alem de emitir relatórios e permitir atachar uma versão.

Voltando versões de um arquivo

Para voltar a versão de um arquivo, selecione a versão que você deseja que seja recuperada e clique em rollback.

Page 29: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

controlador de versoes

29

O Source Safe irá exibir uma janela de alerta informando que algumas versões (as intermediárias entre a última versão e a versão que está sendo recuperada) serão perdidas. Confirme clicando em “Yes”.

Note na figura abaixo que a versão 2 do arquivo foi perdida e não poderá mais ser recuperada.

IMPORTANTE: Tenha cuidado ao utilizar RollBack, pois as versões inter-mediárias sempre são perdidas.

Comparando Versões de Arquivos – (Show History / Show Differences...)

Podemos visualizar também as diferenças entre as versões de um mesmo arquivo, isso sempre auxilia quando precisamos identificar um bug de um arquivo de código fonte ou apenas para visualizar as diferenças de uma versão para outra de um mesmo arquivo.

Para ver as diferenças entre versões de um mesmo arquivo, selecione o arquivo e peça o a janela de histórico de versões, utilize a tecla CTRL para selecionar as duas versões do arquivo e clique em “Diff”

O Source Safe exibirá a janela “Difference Options”, nela você poderá configurar as diferenças que você quer considerar na análise.

A melhor forma para se analisar diferenças de conteúdo dos arquivos texto de forma visual é manter a janela configurada com o a imagem acima.

Clique em “OK” e o Source Safe exibirá a janela com os dois arquivos selecionados e as diferenças entre eles serão descritas por fontes de cores diferentes, observe a legenda abaixo da janela.

Comparando Diretórios e Projetos – (Show Differences...)

Você poderá ainda comparar um projeto do Source Safe com um outro projeto no Source Safe ou com uma versão que esteja em um diretório no

Page 30: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um

controlador de versoes

30

HUMOR

sistema operacional, para isso selecione o projeto que deseja comparar, clique com o botão direito e selecione “Show Differences...”, o Source Safe exibirá a janela “Project Diferences”.

Note que nos campos “Compare” e “To” podem ser selecionados tanto

projetos no Source Safe como diretórios do sistema operacional, selecione o projeto ou diretório do sistema operacional que deseja comparar, marque a opção “Recursive” para que o Source Safe considere sub-projetos ou sub-diretórios e compare recursivamente toda a estrutura e clique em “Ok”.

A janela exibida, mostra todas as diferenças entre as estruturas com-paradas. Utilize o botão “Reconcile All” para criar uma equivalência entre as versões, baixando os arquivos que não estão no diretório comparado e subindo os diretórios e arquivos que estão no diretório comparado e não estão no

Sobre o autorFabio Camara ([email protected]) é MCT,

MCP, MCSA, MCAD Charter, MCITP, MCTS, MCSD.NET, MSF Practitioner, Certified ITIL Foundations e Certified SCRUM Master– Acredita em bons resultados em projetos com técni-cas ágeis, principalmente para as características do mercado brasileiro.

projeto do source safe. Essa é uma boa tática para subir grandes conteúdos para uma base do Source Safe, principalmente se as estruturas forem muito complexas e cheia de sub-diretórios.

Page 31: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um
Page 32: Editorial - The Club · Desde a linguagem Clipper, passando pelo Delphi e inúmeros programas relacionados, até o ASP.NET e algumas ... guntando o por que disso e achando até um