segunda-feira, 25 de março de 2013

Delphi: Executando Componentes de Banco de Dados

Como executar uma Query no Delphi
Alguns programadores iniciantes ao inserir um Query no Data Module da Aplicação simplesmente altera o Campo SQL para executar a operação desejada, porém a forma mais eficaz e executá-la no corpo do programa, assim como as stored procedures

Execução de Query no Delphi

qry.Close; 
qry.SQL.Clear; 
qry.SQL.Add(passe aqui o sql da lista); 
qry.ExecSQL;

Execução de Stored Procedures no Delphi

 CREATE PROCEDURE ATUALIZA_PRECO_VND_PRD ( 
id_produto integer, 
margem_lucro decimal(15,4)) 
as 
begin 
update tabprodutos 
set preco_venda = preco_custo + (preco_custo * :margem_lucro)/100 
where id_produto = :id_produto; 
suspend; 
end^ 

SET TERM ; ^ 

with qrylocal do 
  begin 
    close; 
    sql.clear; 
    sql.add(' EXECUTE PROCEDURE ATUALIZA_PRECO_VND_PRD (:id_produto,:margem_lucro decimal)'); 
    Params[0].asinteger    :=  inttostr(dbe_produto.text); 
    Params[1].ascurrency  :=  inttofloat(dbe_margemLucro.text); 
    try 
      execsql; 
      dm.connection.commit; 
    except 
      dm.connection.rollback; 
    end; 
  end;

lQuery := TQuery.Create(nil);     
try
  lQuery.SQL.Clear;
  lQuery
.SQL.Add('exec fn_ResolucaoPessoa: TipoPesquisa: NomePessoa: CPF: RG: DataNascimento: NomeMae');
  
lQuery.Parameters.ParamByName('TipoPesquisa').Value := rgOpcoes.ItemIndex;
  
lQuery.Parameters.ParamByName('NomePessoa').Value := EditNome.Text;
  
lQuery.Parameters.ParamByName('CPF').Value := EditCPF.Text;
  
lQuery.Parameters.ParamByName('RG').Value := EditRG.Text;
  
lQuery.Parameters.ParamByName('DataNascimento').Value := EditDataNasc.Date;
  
lQuery.Parameters.ParamByName('NomeMae').Value := EditNomeMae.Text;
  
lQuery.ExecSQL;finally
  lQuery.Free;
end; 

MySQL: como auto incrementar?

Essa é a mais fácil de todas.


Acrescente a palavra auto_increment após o nome do atributo, mas cuidado com a ignorância, o auto incremento não funcionará em atributos CHAR,VARCHAR,TEXT...

veja o exemplo...


create table venda (
numero integer not null auto_increment,
data date,
primary key(numero)
);

MySQL: Como criar e executar Stored Procedures

Stored procedures são procedimentos armazenados, ou seja inserts, updates, deletes ou select que você cria e que armazena para poder executar com parâmetros ou não

Criando Storeds Procedures no MySQL

usaremos como exemplo a tabela venda abaixo


create table venda(
codVenda   int,
data       date,
total      float,
primary key(codvenda)
)



DELIMITER $$

CREATE procedure InserirVenda(cdv int,dt date,tot float)
BEGIN
    insert into itensvenda(codVenda,data,total) 
    values(cdv,dt,tot); 
END$$
DELIMITER ;


EXECUTANDO

call InserirVenda(1,2013-03-03,10)


Fácil! não? 
stored procedure é muito fácil, vc só precisa informar onde ela começa e termina com "DELIMITER $$" dá um nome a ela e entre o begin e o end colocar o que desejar, inserir, deletar, atualizar...

MySQL: Como Criar Triggers

Criar uma trigger é muito parecido em qualquer que seja o banco de dados que você esteja utilizando, SQL Server, Oracle, Firebird, MySQL... O importante é que você saiba para que serve e  quando utilizar, sabendo isso vem a segunda pergunta: como criar?

O que é uma Trigger
Traduzindo para o português, trigger significa gatilho e se relacionam direto com as tabelas através de comandos como UPDATE, INSERTE e DELETE

Sintaxe


CREATE TRIGGER "nome momento evento"
ON tabela
FOR EACH ROW
BEGIN
/*corpo do código*/
END


Onde e usar uma Trigger

EX: Para as tabelas vendas(Data, ValorTotal) e Itens_Venda(ValorUnitario, QuantidadeItens)  queremos que cada vez que um item for inserido na tabela Itens_Venda o ValorTotal da tabela Venda incremente o mesmo valor então..

Criamos uma trigger IncrementaValorVenda para disparar sempre que um item for adicionado na tabela Itens_venda.

create table venda(
codVenda integer
data date,
ValorTotal integer,
primary key(codVenda)
)

create table ItensVenda(
 ValorUnitario   integer,
 QuantidadeItens Interger,
cod_Venda Integer,
foreign key (cod_venda) references venda(codVenda)
)


DELIMITER $$
 
CREATE TRIGGER Tgr_Itens_Venda_Insert AFTER INSERT
ON Itens_Venda
FOR EACH ROW
BEGIN
    UPDATE venda SET ValorTotal = ValorTotal + NEW.ValorUnitario
    WHERE Cod_venda = NEW.Codvenda;
END$$
 
CREATE TRIGGER Tgr_ItensVenda_Delete AFTER DELETE
ON Itens_Venda
FOR EACH ROW
BEGIN
    UPDATE venda SET ValorTotal = ValorTotal - OLD.ValorUnitario
    WHERE Cod_venda = OLD.Codvenda;
END$$
 
DELIMITER ;


Note que foi criado dois gatilhos, o primeiro Tgr_Itens_Venda_Insert será disparado sempre que for inserido um novo item em Itens_venda  fazendo com que ela some no total da tabela venda e o segundo Tgr_ItensVenda_Delete será disparado cada vez que for deletado um item da tabela Itens_venda. você também poderia criar um para cada vez que for atualizada a tabela itens_venda


AFTER e BEFORE(ANTES E DEPOIS)

No exemplo acima o gatilho será disparado depois que for feia uma inserção na tabela itens_Venda porém se usasse o comando BEFORE, o gatilho seria disparado antes da inserção.

Usamos BEFORE normalmente para fazer consultas complexas na tabela antes de inserir algo nela, ex: antes de inserir vendas quero verificar a data da tabela.


Espero ter ajudado, qualquer dúvida comentem....




sexta-feira, 15 de março de 2013

Tratamento de erros no Delphi (Try, Except, Finally, Raise, Exception e ApplicationEvents)

É impossível criar um software e nunca ocorrer um erro durante a execução do mesmo, as vezes por algum defeito na rede, ou por o usuário não seguir corretamente a maneira correta de uso do software.
Como, não podemos impedir que os erro ocorram em nossas aplicações, devemos no mínimo tratar e personalizar as mensagens de erro para que o usuário saiba o motivo do erro e assim agir da forma correta para corrigir. 

Exceções em Delphi 

São utilizadas para tratamento de erros, e ao ser criada todos os procedimentos que ainda estão pendentes são cancelados, e mostra uma mensagem de erro que você mesmo poderá configurar para ser exibida de acordo com a sua vontade


Bloco Protegido

Um bloco protegido é um grupo de comandos com uma seção de tratamento de exceções.


Try 
  A := StrToFloat(EdtA.Text);   B := StrToFloat(EdtB.Text); 
  ShowMessage(Format("%f / %f = %f", [A, B, A + B])); 
Except 
  ShowMessage("Números inválidos."); 
end;


As vezes você pode precisar especificar quais exceções quer tratar, como mostrado abaixo:

Try 
  Soma := StrToFloat(EdtSoma.Text); 
  NumAlunos := StrToInt(EdtNum.Text); 
  ShowMessage(Format("Média igual a %f.", [Soma / NumAlunos])); except
 on EConvertError do 
   ShowMessage("Valor inválido para soma ou número de alunos."); 
 on EZeroDivide do 
   ShowMessage("O número de alunos tem que ser maior que zero.");
 else 
 ShowMessage("Erro na operação, verifique os valores digitados."); end;

Principais Exceções

CLIQUE NA IMAGEM PARA AMPLIAR



Blocos de finalização 

são executados sempre, haja ou não uma exceção. Geralmente os blocos de finalização são usados para liberar recursos.

FrmSobre := TFrmSobre.Create(Application); 
 Try 
  FrmSobre.Img.LoadFromFile("Delphi.bmp");
  FrmSobre.ShowModal; 
  finally 
   FrmSobre.Release; 
end;

Você pode usar blocos de proteção e finalização aninhados 


FrmOptions := TFrmOptions.Create(Application); 
 Try 
   FrmOptions.ShowModal; 
  Try 
   Tbl.Edit; 
   TblValor.AsString := EdtValor.Text; 
    except 
      on EDBEngineError do 
         ShowMessage("Alteração não permitida."); 
      on EConvertError do 
         ShowMessage("Valor inválido."); 
  end; 
     finally 
      FrmOptions.Release; 
end;


Geração de Exceções

provocando uma exceção utilizando a cláusula raise.
    raise EDatabaseError.Create("Erro ao alterar registro.");


Também é possível criar seus próprios tipos de exceções.
  type 
  EInvalidUser = class (Exception); 
  raise EInvalidUser.Create("Você não tem acesso a essa operação.");


Se você quiser que uma exceção continue ativa, mesmo depois de tratada, use a cláusula raise dentro do bloco de tratamento da exceção. Geralmente isso é feito com exceções aninhadas.

try 
   Tbl.Edit; 
   TblContador.Value := TblContador.Value + 1;
   Tbl.Post; 
  except 
    ShowMessage("Erro ao alterar contador."); 
  raise; 
end; 


Erros de Bancos de Dados

A exceção EDBEngineError permite a identificação de erros de bancos de dados gerados pela BDE.

try 
 TblCli.Post; 
  except 
   on E: EDBEngineError do 
   if E.Errors[0].ErrorCode = DBIERR_KEYVIOL then
    ShowMessage("Cliente já cadastrado."); 
end;

Note que a variável E, que vai identificar o erro, só precisa ser declarada no bloco de tratamento da exceção. No help você pode consultar outras propriedades de EDBEngineError que podem ser importantes.

Você também pode usar os eventos de erro do componente Table, sem precisar de blocos de tratamento.

procedure TFrmCadCli.TblCliPostError(DataSet: TDataSet; E: EDatabaseError; Action: TDataAction); 
var 
 begin 
  if(E is EDBEngineError) then 
   with EDBEngineError(E) do 
    case Errors[0].ErrorCode of 
     DBIERR_KEYVIOL: ShowMessage("Cliente já cadastrado.");
     DBIERR_REQDERR: ShowMessage("Campo obrigatório não preenchido.");
    end 
    else 
       ShowMessage("Erro no banco de dados:" + #13#13 + E.Message); 
       Action := daAbort; 
end;

Alguns códigos de erro da BDE estão listados abaixo. Todas as constantes e funções relacionadas à API da BDE no Delphi 3 estão na Unit BDE, que deve ser adicionada à cláusula uses. No BDE API Help você pode encontrar referência sobre as funções nativas da BDE, como também alguns exemplos em Delphi.

CLIQUE NA IMAGEM PARA AMPLIAR
Se você quiser mais informações a respeito do erro pode usar o procedimento DBIGetErrorContext, como na função mostrada abaixo que retorna determinadas informações sobre o erro.

function GetErrorInfo(Context: SmallInt):string; 
  begin 
    SetLength(Result, DBIMAXMSGLEN + 1); 
   try 
    DbiGetErrorContext(Context, PChar(Result)); 
    SetLength(Result, StrLen(PChar(Result)));
    except 
     Result := ""; 
   end; 
  end; 


No evento OnEditError, usado no exemplo abaixo, se ocorrer um erro ao tentar alterar um registro, podemos identificar o usuário da rede que está alterando esse registro usando a função criada anteriormente.

if Pos("locked", E.Message)> 0 then 
 ShowMessage("Usuário """ + GetErrorInfo(ecUSERNAME) + """ está alterando o registro."); 

Note que foi usada uma outra técnica de identificação do erro, usando a própria mensagem de erro e não o código, como mostrado anteriormente. Você pode usar a função criada acima mandando como parâmetro os valores mostrados abaixo, que podem ser encontrados no help da BDE.
CLIQUE NA IMAGEM PARA AMPLIAR

Para desenvolver um sistema genérico de tratamento de erros, considere a opção de criar esse tratamento em um DataModule genérico para ser usado como ancestral por todos os DataModules do sistema, utilizando a herança visual.
Se o único problema for traduzir as mensagens, localize os arquivos CONSTS.INT e DBCONSTS.INT e crie uma nova Unit de definição de strings com uma estrutura semelhante a mostrada abaixo e juntando todas as definições das constantes das duas Units devidamente traduzidas. Depois, basta usar essa Unit em seus projetos que as novas mensagens irão sobrepor as anteriores.
unit NewConsts;

interface

resourcestring
SAssignError = "Não é possível atribuir %s a %s";
SFCreateError = "Não é possível criar arquivo %s";
SFOpenError = "Não é possível abrir arquivo %s";
iSInvalidFieldSize = "Tamanho de campo inválido"; SInvalidFieldRegistration = "Registro de campo inválido";
SUnknownFieldType = "Campo ""%s"" tem um tipo desconhecido";

 implementation 

end.