Ajuda em criar uma camada de persistencia?

Delphi

05/05/2011

Pessoal, não sei se estou fazendo certo, mais queria criar algo para insert, delete, update e select cfe esta função
Mais estou com problema em montar os PARAMBYNAME no SQL (destaque em azul e em vermelho no CODE abaixo.
//iTypeCommand - 1 Insert, 2 Update, 3 - Delete - 4 select
function TDataModule2.ExecuteSQL(Query: TIBQuery; TableName: String; iTypeCommand: Integer): Boolean ;
var
  i, iPos: integer;
  sSQL, sInsert, sValues, sCreateFields, sVariavel: String;
  sCreateParams: TStringList;
  sCreateParamByName: String;
begin
  sCreateParams := TStringList.Create;
  try
    try
      //Verifica se a conexão esta OK
      if not IBDatabase1.Connected then
        IBDatabase1.Connected := True;
      //Faz um select da tabela para saber quis são os campos
      Query.SQL.Text := 'SELECT * FROM '+TableName;
      Query.Open;
      //Conta a quantidade de campos da tabela selecionada
      for i := 0 to Pred(Query.Fields.Count) do
      begin
        //Se o iTypeCommand for = 1 então monta o insert
        if iTypeCommand = 1 then
        begin
          if i < Pred(Query.Fields.Count) then
          begin
            sCreateFields := sCreateFields + Query.Fields[i].FieldName + ' = :' + Query.Fields[i].FieldName + ',';
            sValues := sValues + ':' + Query.Fields[i].FieldName + ',';
            sInsert := sInsert + Query.Fields[i].FieldName + ',';
          end
          else
          begin
            sCreateFields := sCreateFields + Query.Fields[i].FieldName + ' = :' + Query.Fields[i].FieldName;
            sInsert := sInsert + Query.Fields[i].FieldName;
            sValues := sValues + ':' + Query.Fields[i].FieldName;
          end;
        end
        else
        // Se o iTypeCommand for = 2 então monta o Update
        if iTypeCommand = 2 then
        begin
          if i < Pred(Query.Fields.Count) then
          begin
            sCreateFields := sCreateFields + Query.Fields[i].FieldName + ' = :' + Query.Fields[i].FieldName + ',';
            sValues := sValues + ':' + Query.Fields[i].FieldName + ',';
            sInsert := sInsert + Query.Fields[i].FieldName + ',';
          end
          else
          begin
            //Recorto a primeira posição do campo antes da virgula
            iPos := Pos(',', sCreateFields);
            if iPos > 0 then
               Delete(sCreateFields, 1, iPos);
            //
            sCreateFields := sCreateFields + Query.Fields[i].FieldName + ' = :' + Query.Fields[i].FieldName;
            sInsert := sInsert + Query.Fields[i].FieldName;
            sValues := sValues + ':' + Query.Fields[i].FieldName;
          end;
        end
        else
        // Se o iTypeCommand for = 4 então monta o SELECT
        if iTypeCommand = 4 then
        begin
          if i < Pred(Query.Fields.Count) then
          begin
            sInsert := sInsert + Query.Fields[i].FieldName + ',';
          end
          else
          begin
            sInsert := sInsert + Query.Fields[i].FieldName;
          end;
        end;
      end;
      //passa a instrução SQL para o comando cfe o iTypeCommand (1-Insert, 2-Update, 3-Delete - 4 select)
      case iTypeCommand of
        //Insert
        1: sSQL := 'INSERT INTO '+ TableName +' (' + sInsert + ' ) VALUES ( '+ sValues + ' )';
        //Update
        2: sSQL := 'UPDATE '+ TableName +' SET '+ sCreateFields +' WHERE '+ Query.Fields[0].FieldName + ' = :OLD_' + Query.Fields[0].FieldName;
        //Delete
        3: sSQL := 'DELETE FROM ' + TableName + ' WHERE ' + Query.Fields[0].FieldName + ' = :OLD_' + Query.Fields[0].FieldName;
        //Select
        4: sSQL := 'SELECT '+ sInsert + ' FROM '+ TableName + ' WHERE ' + Query.Fields[0].FieldName + ' = ' + Query.Fields[0].FieldName;
      end;
      //Agora monta os parametros
      case iTypeCommand of
        //Insert
        1:
        begin
          for i := 0 to Pred(Query.Fields.Count) do
          begin
            //Se o iTypeCommand for = 1 então monta o insert
            if iTypeCommand = 1 then
            begin
              sCreateParamByName := sCreateParamByName + 'ParamByName(":' + Query.Fields[i].FieldName + '").Value' +
                  ' = ' + 'Teste Variavel' +';'+#10#13; //sVariavel;
            end;
          end;
        end;        { //Update         2:         //Delete         3:         //Select         4:  }       end;         with Query do         begin           Close;           SQL.Clear;           SQL.Add(sSQL);           sCreateParamByName;           excSQL; // ou Open         end;         Result := True;     except       Result := False;     end;   finally     sCreateParams.Free;   end; end;
Como é a forma correta de fazer isso?

Obrigado pessoal.
Adriano Dolce

Adriano Dolce

Curtidas 0

Respostas

Adriano Dolce

Adriano Dolce

05/05/2011

Corrigindo a parte azul, tinha dois pontos que não é necessário
 for i := 0 to Pred(Query.Fields.Count) do
          begin
            //Se o iTypeCommand for = 1 então monta o insert
            if iTypeCommand = 1 then
            begin
              sCreateParamByName := sCreateParamByName + 'ParamByName("' + Query.Fields[i].FieldName + '").Value' +
                  ' = ' + 'Teste Variavel' +';'+#10#13; //sVariavel;
            end;


Então este é o resultado deste bloco ai
ParamByName("EMP_NO").Value = Teste Variavel;'#$A#$D'ParamByName("FIRST_NAME").Value = Teste Variavel;'#$A#$D'ParamByName("LAST_NAME").Value = Teste Variavel;'#$A#$D'ParamByName("PHONE_EXT").Value = Teste Variavel;'#$A#$D'ParamByName("HIRE_DATE").Value = Teste Variavel;'#$A#$D'ParamByName("DEPT_NO").Value = Teste Variavel;'#$A#$D'ParamByName("JOB_CODE").Value = Teste Variavel;'#$A#$D'ParamByName("JOB_GRADE").Value = Teste Variavel;'#$A#$D'ParamByName("JOB_COUNTRY").Value = Teste Variavel;'#$A#$D'ParamByName("SALARY").Value = Teste Variavel;#$A#$D
GOSTEI 0
Adriano Dolce

Adriano Dolce

05/05/2011

Apenas estou postando para informar que mudei a função para chamar um enumerado no lugar de um integer, e alguns comandos de if mudei para case

TTipoComando = (tcInsert, tcUpdate, tcDelete, tcSelect);


function TDataModule2.ExecuteSQL(Query: TIBQuery; TableName: String;
  iTypeCommand: TTipoComando): Boolean;
var
  i, iPos: integer;
  sSQL, sInsert, sValues, sCreateFields, sVariavel: String;
  sCreateParams: TStringList;
  sCreateParamByName: String;
begin
  sCreateParams := TStringList.Create;
  try
    try
      //Verifica se a conexão esta OK
      if not IBDatabase1.Connected then
        IBDatabase1.Connected := True;
      //Faz um select da tabela para saber quis são os campos
      Query.SQL.Text := 'SELECT * FROM '+TableName;
      Query.Open;
      //Conta a quantidade de campos da tabela selecionada
      for i := 0 to Pred(Query.Fields.Count) do
      begin
        case iTypeCommand of
          tcInsert:
            begin
              sCreateFields := sCreateFields + Query.Fields[i].FieldName + ' = :' + Query.Fields[i].FieldName + ',';
              sInsert := sInsert + Query.Fields[i].FieldName + ',';
              sValues := sValues + ':' + Query.Fields[i].FieldName + ',';
            end;
          tcUpdate:
            begin
              sCreateFields := sCreateFields + Query.Fields[i].FieldName + ' = :' + Query.Fields[i].FieldName + ',';
            end;
          tcSelect:
            begin
              sCreateFields := Query.Fields[i].FieldName + ',';
              sInsert := sInsert + Query.Fields[i].FieldName + ',';
            end;
        end;
      end;
      //Final do Loop
      case iTypeCommand of
        tcInsert:
          begin
            //recorto a ultima virgula da montagem do SQL
            Delete(sInsert, Length(sInsert), 1);
            Delete(sValues, Length(sValues), 1);
          end;
        tcUpdate:
          begin
            //Recorto a primeira posição do campo antes da virgula
            //pois a PK não é modificado no Update
            iPos := Pos(',', sCreateFields);
            if iPos > 0 then
              Delete(sCreateFields, 1, iPos);
            //recorto também a ultima virgula da montagem do SQL
            Delete(sCreateFields, Length(sCreateFields), 1);
          end;
        //recorto a ultima virgula da montagem do SQL
        tcSelect: Delete(sInsert, Length(sInsert), 1);
      end;
      //passa a instrução SQL para o comando cfe o iTypeCommand (1-Insert, 2-Update, 3-Delete - 4 select)
      case iTypeCommand of
        tcInsert: sSQL := 'INSERT INTO '+ TableName +' (' + sInsert + ' ) VALUES ( '+ sValues + ' )';
        tcUpdate: sSQL := 'UPDATE '+ TableName +' SET '+ sCreateFields +' WHERE '+ Query.Fields[0].FieldName + ' = :OLD_' + Query.Fields[0].FieldName;
        tcDelete: sSQL := 'DELETE FROM ' + TableName + ' WHERE ' + Query.Fields[0].FieldName + ' = :OLD_' + Query.Fields[0].FieldName;
        tcSelect: sSQL := 'SELECT '+ sInsert + ' FROM '+ TableName + ' WHERE ' + Query.Fields[0].FieldName + ' = ' + Query.Fields[0].FieldName;
      end;
      //Agora monta o SQL na query
      case iTypeCommand of
        tcInsert, tcUpdate:
        begin
          for i := 0 to Pred(Query.Fields.Count) do
          begin
            sCreateParamByName := sCreateParamByName + 'ParamByName("' + Query.Fields[i].FieldName + '").Value' +
                ' = ' + 'Teste Variavel' +';'+#10#13; //sVariavel;
          end;
        end;
       {tcDelete:
        tcSelect:  }
      end;
      //Monta o SQL
      with Query do
      begin
        Close;
        SQL.Clear;
        SQL.Add(sSQL);
        //sCreateParamByName;
        ExecSQL; // ou Open
      end;
      Result := True;
    except
      Result := False;
    end;
  finally
    sCreateParams.Free;
  end;
end;


Mais a duvida de como fazer algo que dê para passar parametros para montar o SQL continua, estou vendo que é algo meio que impossivel de ser feito desta forma, mais então como seria a forma que o pessoal monta esta tal de PERSISTENCIA?

GOSTEI 0
Adriano Dolce

Adriano Dolce

05/05/2011

Bom pessoal, mudei o código todo aqui assim:
Na camada de persistencia mudei a função, agora retorna um string
function TDataModule2.ExecuteSQL(Query: TIBQuery; TableName: String;
  iTypeCommand: TTipoComando; xEmployee: TEmployee): String;
var
  i, iPos: integer;
  sInsert, sValues, sCreateFields, sVariavel: String;
  sCreateParams: TStringList;
  sCreateParamByName: String;
begin
  sCreateParams := TStringList.Create;
  try
    try
      //Verifica se a conexão esta OK
      if not IBDatabase1.Connected then
        IBDatabase1.Connected := True;
      //Faz um select da tabela para saber quis são os campos
      Query.SQL.Text := 'SELECT * FROM '+TableName;
      Query.Open;
      //Conta a quantidade de campos da tabela selecionada
      for i := 0 to Pred(Query.Fields.Count) do
      begin
        case iTypeCommand of
          tcInsert:
            begin
              sCreateFields := sCreateFields + Query.Fields[i].FieldName + ' = :' + Query.Fields[i].FieldName + ',';
              sInsert := sInsert + Query.Fields[i].FieldName + ',';
              sValues := sValues + ':' + Query.Fields[i].FieldName + ',';
            end;
          tcUpdate:
            begin
              sCreateFields := sCreateFields + Query.Fields[i].FieldName + ' = :' + Query.Fields[i].FieldName + ',';
            end;
          tcSelect:
            begin
              sCreateFields := Query.Fields[i].FieldName + ',';
              sInsert := sInsert + Query.Fields[i].FieldName + ',';
            end;
        end;
      end;
      //Final do Loop
      case iTypeCommand of
        tcInsert:
          begin
            //recorto a ultima virgula da montagem do SQL
            Delete(sInsert, Length(sInsert), 1);
            Delete(sValues, Length(sValues), 1);
          end;
        tcUpdate:
          begin
            //Recorto a primeira posição do campo antes da virgula
            //pois a PK não é modificado no Update
            iPos := Pos(',', sCreateFields);
            if iPos > 0 then
              Delete(sCreateFields, 1, iPos);
            //recorto também a ultima virgula da montagem do SQL
            Delete(sCreateFields, Length(sCreateFields), 1);
          end;
        //recorto a ultima virgula da montagem do SQL
        tcSelect: Delete(sInsert, Length(sInsert), 1);
      end;
      //passa a instrução SQL para o comando cfe o iTypeCommand 
      case iTypeCommand of
        tcInsert: Result := 'INSERT INTO '+ TableName +' (' + sInsert + ' ) VALUES ( '+ sValues + ' )';
        tcUpdate: Result := 'UPDATE '+ TableName +' SET '+ sCreateFields +' WHERE '+ Query.Fields[0].FieldName + ' = :' + Query.Fields[0].FieldName;
        tcDelete: Result := 'DELETE FROM ' + TableName + ' WHERE ' + Query.Fields[0].FieldName + ' = :' + Query.Fields[0].FieldName;
        tcSelect: Result := 'SELECT '+ sInsert + ' FROM '+ TableName + ' WHERE ' + Query.Fields[0].FieldName + ' = ' + Query.Fields[0].FieldName;
      end;
    except
      on E:Exception do
      begin
        raise Exception.Create('Erro! '+ E.Message);
        Result := EmptyStr;
      end;
    end;
  finally
    sCreateParams.Free;
  end;
end;

Na camada ne negocio criei 4 funções que chamam a função da persistencia e criei uma função ja com os selects e parametros.

As funções que chamam a função da persistencia ficou assim
function TEmployee.ExecuteInsertSQL: String;
begin
  Result := DataModule2.ExecuteSQL(DataModule2.qry_Temp,'XEMPLOYEE',tcInsert,Self)
end;

function TEmployee.ExecuteUpdateSQL: String;
begin
 Result := DataModule2.ExecuteSQL(DataModule2.qry_Temp,'XEMPLOYEE',tcUpdate,Self)
end;

function TEmployee.ExecuteDeleteSQL: String;
begin
  Result := DataModule2.ExecuteSQL(DataModule2.qry_Temp,'XEMPLOYEE',tcDelete,Self)
end;

function TEmployee.ExecuteSelectSQL: String;
begin
  Result := DataModule2.ExecuteSQL(DataModule2.qry_Temp,'XEMPLOYEE',tcSelect,Self)
end;


e a que passa os parametros ficou assim (tem TFields incompletos, esta apenas pra teste) Poderia passar direto sem utilizar a variavel sSQL, mais é pq gosto de utilizar variaveis.
procedure TEmployee.ExecuteParams(Query: TIBQuery; iTypeCommand: TFormaComando);
var
 sSQL: String;
begin
  try
    case iTypeCommand of
      fcInsert : sSQL := ExecuteInsertSQL;
      fcUpdate : sSQL := ExecuteUpdateSQL;
      fcDelete : sSQL := ExecuteDeleteSQL;
      fcSelect : sSQL := ExecuteSelectSQL;
    end;
    //Passa os parametros
    Query.Close;
    Query.SQL.Clear;
    Query.SQL.Add(sSQL);
    Query.ParamByName('Emp_No').Value      := FEmp_No;
    //Para o comando delete não precisa passar os parametros
    if not(iTypeCommand = fcDelete) then
    begin
      Query.ParamByName('First_Name').Value  := FFirst_Name;
      Query.ParamByName('Last_name').Value   := FLast_name;
      Query.ParamByName('Phone_Ext').Value   := FPhone_Ext;
      Query.ParamByName('Hire_date').Value   := Date; //FHire_date;
      Query.ParamByName('Dept_No').Value     := 900;//xEmployee.Dept_No;
      Query.ParamByName('Job_Code').Value    := 'CFO'; //xEmployee.Job_Code;
      Query.ParamByName('Job_Grade').Value   := 3; //xEmployee.Job_Grade;
      Query.ParamByName('Job_Country').Value := 'BRASIL'; //xEmployee.Job_Country;
      Query.ParamByName('Salary').Value      := FSalary;
    end;  
    //Verifica que tipo de comando deve executar
    case iTypeCommand of
      fcInsert, fcUpdate, fcDelete: Query.ExecSQL;
      fcSelect: Query.Open;
    end;
    if not DataModule2.IBTransaction1.Active then
      DataModule2.IBTransaction1.Active := True;
    DataModule2.IBTransaction1.Commit;
  except
    on E:Exception do
    begin
      raise Exception.Create('Erro! '+ E.Message);
      DataModule2.IBTransaction1.Rollback;
    end;
  end;
end;


Na camada de interface chamo assim
procedure Tfrm_cadastro.btnInsertClick(Sender: TObject);
var
  OK: Boolean;
begin
  //No método Set eu escrevo as variaveis para o banco de dados
  SetExecute;
  try
    //aqui executo o select com seus parametros que fica na classe de negocio
    xEmployee.ExecuteParams(DataModule2.qry_Temp,fcInsert);
    if OK then
    begin
      LimparCampos(True);
      xEmployee.Limpar;
    end;
  except
    raise Exception.Create('Erro! Não foi possível executar este processo.');
    edt_Codigo.SetFocus;
  end;  
end;

procedure Tfrm_cadastro.btnUpdateClick(Sender: TObject);
var
  OK: Boolean;
begin
   //No método Set eu escrevo as variaveis para o banco de dados
  SetExecute;
  try
    //aqui executo o select com seus parametros que fica na classe de negocio
    xEmployee.ExecuteParams(DataModule2.qry_Temp,fcUpdate);
    if OK then
    begin
      LimparCampos(True);
      xEmployee.Limpar;
    end;
  except
    on E:Exception do
    begin
      raise Exception.Create('Erro! '+ E.Message);
    //raise Exception.Create('Erro! Não foi possível executar este processo.');
      edt_Codigo.SetFocus;
    end;
  end;
end;

procedure Tfrm_cadastro.btnDeleteClick(Sender: TObject);
var
  OK: Boolean;
begin
   //No método Set eu escrevo as variaveis para o banco de dados
  SetExecute;
  try
    //aqui executo o select com seus parametros que fica na classe de negocio
    xEmployee.ExecuteParams(DataModule2.qry_Temp,fcDelete);
    if OK then
    begin
      LimparCampos(True);
      xEmployee.Limpar;
    end;
  except
    raise Exception.Create('Erro! Não foi possível executar este processo.');
    edt_Codigo.SetFocus;
  end;
end;

procedure Tfrm_cadastro.btnSelectClick(Sender: TObject);
var
  OK: Boolean;
begin
   //No método Set eu escrevo as variaveis para o banco de dados
  SetExecute;
  try
    //aqui executo o select com seus parametros que fica na classe de negocio
    xEmployee.ExecuteParams(DataModule2.qry_Temp,fcSelect);
    if OK then
    begin
      LimparCampos(True);
      xEmployee.Limpar;
    end;
  except
    raise Exception.Create('Erro! Não foi possível executar este processo.');
    edt_Codigo.SetFocus;
  end;
end;


e criei nesta camada uma procedure para gravar os dados para o banco que resolvi chamar de SetExecute (Não sei bem se o nome correspone,pois até hj confundo muito os métodos get (ler) e set (escrever)) :D
procedure Tfrm_cadastro.SetExecute;
begin
  (* aqui estou escrevendo (GRAVANDO) para o banco o valor das variaveis *)
  xEmployee.Emp_No      := StrToInt(edt_Codigo.Text);
  xEmployee.First_Name  := edt_nome.Text;
  xEmployee.Last_name   := edt_sobrenome.Text;
  xEmployee.Phone_Ext   := '41-8815-6366';
  xEmployee.Hire_date   := Date;
  xEmployee.Dept_No     := 11;
  xEmployee.Job_Code    := 'BRA';
  xEmployee.Job_Grade   := 155;
  xEmployee.Job_Country := 'STR TRY';
  xEmployee.Salary      := StrToCurr(edt_salario.Text);
end;


Falta passar alguns edits ainda.

Bom desta forma ai, vai dar trabalho pq cada propriedades de interface que eu criar devo setar o parametros...

Foi isso que eu imaginei, que da pra fazer.

GOSTEI 0
José

José

05/05/2011

Este tópico esta sendo fechado por inatividade. Se necessário, sinalizar para que seja reaberto ou abrir um novo.
GOSTEI 0
POSTAR